You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Part of #7445 — this is the foundation issue; the other sub-tasks depend on it.
Summary
Add a Prometheus /metrics HTTP endpoint to the v2 app framework and initialize the metrics Scope on the SetupContext, so every service built on it (runs service first) can expose and emit metrics.
Why
The real gap is that no /metrics endpoint is mounted anywhere.app.App.serve() only serves /healthz and /readyz (flytestdlib/app/app.go:94-109). The v1 pattern using promhttp.Handler() lives in flytestdlib/profutils/server.go:118 but was never wired into the v2 framework. So even though metrics are registered into the default Prometheus registry (storage sub-scope, the actions bloom-filter sub-scope, etc.), nothing serves them — a scrape returns nothing useful.
Secondary: the app framework's serve() never assigns sc.Scope (flytestdlib/app/context.go:62-63). The unified manager sets it (manager/cmd/main.go:75, sc.Scope = promutils.NewScope("flyte")), so services run via the manager get a non-nil scope. But the standalone binaries (runs/cmd/main.go, actions/cmd/main.go) do not set it, so anything reading sc.Scope there gets a nil interface. Initializing it at the framework level removes that footgun and means standalone binaries also get a working scope.
What to do
In flytestdlib/app/app.go, inside Run() where the HTTP server is set up (the if sc.Port > 0 { block, around lines 92-109):
sc.Scope=promutils.NewScope(a.Name) // promutils.NewScope is defined in flytestdlib/promutils/scope.go:540
Pick a sensible, sanitized scope name from the app name (a.Name, e.g. "runs-service"). Note the unified manager already sets sc.Scope = promutils.NewScope("flyte") inside its own setup() (manager/cmd/main.go:75), which runs after the framework default and overrides it — that's fine. Consider only setting the framework default when sc.Scope == nil to make the precedence explicit.
Register the Prometheus handler on the mux next to /healthz and /readyz:
Building and running any app-based service (e.g. runs service) exposes GET /metrics returning Prometheus text format (HTTP 200), including default Go/process collectors.
sc.Scope is non-nil during Setup and after, and is the same scope used to register metrics.
/healthz and /readyz continue to work unchanged.
A unit test in flytestdlib/app/ asserts that /metrics returns 200 and that sc.Scope is initialized.
Pointers
flytestdlib/app/app.go — Run() and the HTTP server block.
flytestdlib/app/context.go:62-63 — the existing Scope field.
Be careful registering metrics only once to avoid Prometheus duplicate-registration panics (use a single shared scope; NewScope + the default registry).
Summary
Add a Prometheus
/metricsHTTP endpoint to the v2appframework and initialize the metricsScopeon theSetupContext, so every service built on it (runs service first) can expose and emit metrics.Why
The real gap is that no
/metricsendpoint is mounted anywhere.app.App.serve()only serves/healthzand/readyz(flytestdlib/app/app.go:94-109). The v1 pattern usingpromhttp.Handler()lives inflytestdlib/profutils/server.go:118but was never wired into the v2 framework. So even though metrics are registered into the default Prometheus registry (storage sub-scope, the actions bloom-filter sub-scope, etc.), nothing serves them — a scrape returns nothing useful.Secondary: the
appframework'sserve()never assignssc.Scope(flytestdlib/app/context.go:62-63). The unified manager sets it (manager/cmd/main.go:75,sc.Scope = promutils.NewScope("flyte")), so services run via the manager get a non-nil scope. But the standalone binaries (runs/cmd/main.go,actions/cmd/main.go) do not set it, so anything readingsc.Scopethere gets a nil interface. Initializing it at the framework level removes that footgun and means standalone binaries also get a working scope.What to do
In
flytestdlib/app/app.go, insideRun()where the HTTP server is set up (theif sc.Port > 0 {block, around lines 92-109):a.Setup(...)is called, so services can usesc.Scopeduring setup (tasks migrate to github actions #2–fix docker flags for workflow #4 register metrics inruns/setup.go):a.Name, e.g."runs-service"). Note the unified manager already setssc.Scope = promutils.NewScope("flyte")inside its ownsetup()(manager/cmd/main.go:75), which runs after the framework default and overrides it — that's fine. Consider only setting the framework default whensc.Scope == nilto make the precedence explicit./healthzand/readyz:"github.com/prometheus/client_golang/prometheus/promhttp".Acceptance criteria
app-based service (e.g. runs service) exposesGET /metricsreturning Prometheus text format (HTTP 200), including default Go/process collectors.sc.Scopeis non-nil duringSetupand after, and is the same scope used to register metrics./healthzand/readyzcontinue to work unchanged.flytestdlib/app/asserts that/metricsreturns 200 and thatsc.Scopeis initialized.Pointers
flytestdlib/app/app.go—Run()and the HTTP server block.flytestdlib/app/context.go:62-63— the existingScopefield.flytestdlib/promutils/scope.go:540—NewScope(name string) Scope.flytestdlib/profutils/server.go:118— reference for how/metricswas served in v1.Notes for contributors
NewScope+ the default registry).