From a4df17d107a46ad361cd7f064a70956839b91a1a Mon Sep 17 00:00:00 2001 From: Victor Chidera Obiezue Date: Thu, 4 Jun 2026 10:33:22 +0100 Subject: [PATCH] fix(flytestdlib): initialize metrics scope and expose /metrics endpoint in v2 app framework Signed-off-by: Victor Chidera Obiezue --- flytestdlib/app/app.go | 7 ++++++ flytestdlib/app/app_test.go | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 flytestdlib/app/app_test.go diff --git a/flytestdlib/app/app.go b/flytestdlib/app/app.go index 49dccb350b..7e37cd12c0 100644 --- a/flytestdlib/app/app.go +++ b/flytestdlib/app/app.go @@ -19,6 +19,8 @@ import ( "github.com/flyteorg/flyte/v2/flytestdlib/config" "github.com/flyteorg/flyte/v2/flytestdlib/config/viper" "github.com/flyteorg/flyte/v2/flytestdlib/logger" + "github.com/flyteorg/flyte/v2/flytestdlib/promutils" + "github.com/prometheus/client_golang/prometheus/promhttp" ) // App is the shared entry-point skeleton for Flyte services. @@ -81,6 +83,11 @@ func (a *App) serve(ctx context.Context) error { Mux: http.NewServeMux(), } + if sc.Scope == nil { + sc.Scope = promutils.NewScope(a.Name) + } + + sc.Mux.Handle("/metrics", promhttp.Handler()) // 3. Let the caller populate resources & register handlers if err := a.Setup(ctx, sc); err != nil { return fmt.Errorf("setup failed: %w", err) diff --git a/flytestdlib/app/app_test.go b/flytestdlib/app/app_test.go new file mode 100644 index 0000000000..b8b7c955f1 --- /dev/null +++ b/flytestdlib/app/app_test.go @@ -0,0 +1,48 @@ +package app + +import ( + "context" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestApp_MetricsEndpointAndScope(t *testing.T) { + var capturedScope interface{} + setupDone := make(chan struct{}) + + testApp := &App{ + Name: "test-metrics-app", + Short: "Testing the metrics framework plumbing", + Setup: func(ctx context.Context, sc *SetupContext) error { + sc.Port = 8099 + capturedScope = sc.Scope + close(setupDone) + return nil + }, + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + go func() { + _ = testApp.serve(ctx) + }() + + select { + case <-setupDone: + case <-time.After(2 * time.Second): + t.Fatal("timed out waiting for app setup") + } + + assert.NotNil(t, capturedScope, "SetupContext.Scope should be initialized by the framework before Setup is called") + + resp, err := http.Get("http://localhost:8099/metrics") + require.NoError(t, err) + defer resp.Body.Close() + + assert.Equal(t, http.StatusOK, resp.StatusCode, "Expected /metrics to return a 200 OK status") +}