From c5943653d54a5603ec9c1607d16833922750dd7b Mon Sep 17 00:00:00 2001 From: "Laurie T. Malau" Date: Mon, 9 May 2022 10:58:01 +0000 Subject: [PATCH] Add request duration metric --- .../public-api-server/pkg/proxy/conn.go | 5 +++ .../pkg/proxy/prometheusmetrics.go | 24 ++++++++++++ .../pkg/proxy/prometheusmetrics_test.go | 38 +++++++++++++++++++ .../pkg/server/integration_test.go | 7 +++- .../public-api-server/pkg/server/server.go | 10 ++++- 5 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 components/public-api-server/pkg/proxy/prometheusmetrics.go create mode 100644 components/public-api-server/pkg/proxy/prometheusmetrics_test.go diff --git a/components/public-api-server/pkg/proxy/conn.go b/components/public-api-server/pkg/proxy/conn.go index d3af9c44903771..60ba383e528382 100644 --- a/components/public-api-server/pkg/proxy/conn.go +++ b/components/public-api-server/pkg/proxy/conn.go @@ -10,6 +10,7 @@ import ( gitpod "github.com/gitpod-io/gitpod/gitpod-protocol" "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus" "net/url" + "time" ) type ServerConnectionPool interface { @@ -26,6 +27,10 @@ type NoConnectionPool struct { func (p *NoConnectionPool) Get(ctx context.Context, token string) (gitpod.APIInterface, error) { logger := ctxlogrus.Extract(ctx) + start := time.Now() + defer func() { + reportConnectionDuration(time.Since(start)) + }() server, err := gitpod.ConnectToServer(p.ServerAPI.String(), gitpod.ConnectToServerOpts{ Context: ctx, Token: token, diff --git a/components/public-api-server/pkg/proxy/prometheusmetrics.go b/components/public-api-server/pkg/proxy/prometheusmetrics.go new file mode 100644 index 00000000000000..4c1ed5fded9e49 --- /dev/null +++ b/components/public-api-server/pkg/proxy/prometheusmetrics.go @@ -0,0 +1,24 @@ +// Copyright (c) 2022 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + +package proxy + +import ( + "github.com/prometheus/client_golang/prometheus" + "time" +) + +func reportConnectionDuration(d time.Duration) { + proxyConnectionCreateDurationSeconds.Observe(d.Seconds()) +} + +var proxyConnectionCreateDurationSeconds = prometheus.NewHistogram(prometheus.HistogramOpts{ + Namespace: "gitpod", + Name: "public_api_proxy_connection_create_duration_seconds", + Help: "Histogram of connection time in seconds", +}) + +func RegisterMetrics(registry *prometheus.Registry) { + registry.MustRegister(proxyConnectionCreateDurationSeconds) +} diff --git a/components/public-api-server/pkg/proxy/prometheusmetrics_test.go b/components/public-api-server/pkg/proxy/prometheusmetrics_test.go new file mode 100644 index 00000000000000..00691cecdd09d0 --- /dev/null +++ b/components/public-api-server/pkg/proxy/prometheusmetrics_test.go @@ -0,0 +1,38 @@ +package proxy + +import ( + "context" + "github.com/gitpod-io/gitpod/common-go/baseserver" + v1 "github.com/gitpod-io/gitpod/public-api/v1" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/stretchr/testify/assert" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/metadata" + "testing" +) + +func TestConnectionCreationWasTracked(t *testing.T) { + // Set up server + srv := baseserver.NewForTests(t) + baseserver.StartServerForTests(t, srv) + + // Set up Prometheus registry + registry := prometheus.NewRegistry() + registry.MustRegister(proxyConnectionCreateDurationSeconds) + + // Set up Workspace client + ctx := metadata.AppendToOutgoingContext(context.Background(), "authorization", "some-token") + conn, err := grpc.Dial(srv.GRPCAddress(), grpc.WithTransportCredentials(insecure.NewCredentials())) + client := v1.NewWorkspacesServiceClient(conn) + + // Call GetWorkspace + client.GetWorkspace(ctx, &v1.GetWorkspaceRequest{ + WorkspaceId: "some-ID", + }) + + count, err := testutil.GatherAndCount(registry) + assert.NoError(t, err) + assert.Equal(t, 1, count) +} diff --git a/components/public-api-server/pkg/server/integration_test.go b/components/public-api-server/pkg/server/integration_test.go index db3f0dc2e3079e..afc585d67bc1d4 100644 --- a/components/public-api-server/pkg/server/integration_test.go +++ b/components/public-api-server/pkg/server/integration_test.go @@ -8,6 +8,7 @@ import ( "context" "github.com/gitpod-io/gitpod/common-go/baseserver" v1 "github.com/gitpod-io/gitpod/public-api/v1" + "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" @@ -21,11 +22,12 @@ import ( func TestPublicAPIServer_v1_WorkspaceService(t *testing.T) { ctx := metadata.AppendToOutgoingContext(context.Background(), "authorization", "some-token") srv := baseserver.NewForTests(t) + registry := prometheus.NewRegistry() gitpodAPI, err := url.Parse("wss://main.preview.gitpod-dev.com/api/v1") require.NoError(t, err) - require.NoError(t, register(srv, Config{GitpodAPI: gitpodAPI})) + require.NoError(t, register(srv, Config{GitpodAPI: gitpodAPI}, registry)) baseserver.StartServerForTests(t, srv) conn, err := grpc.Dial(srv.GRPCAddress(), grpc.WithTransportCredentials(insecure.NewCredentials())) @@ -67,11 +69,12 @@ func TestPublicAPIServer_v1_WorkspaceService(t *testing.T) { func TestPublicAPIServer_v1_PrebuildService(t *testing.T) { ctx := context.Background() srv := baseserver.NewForTests(t) + registry := prometheus.NewRegistry() gitpodAPI, err := url.Parse("wss://main.preview.gitpod-dev.com/api/v1") require.NoError(t, err) - require.NoError(t, register(srv, Config{GitpodAPI: gitpodAPI})) + require.NoError(t, register(srv, Config{GitpodAPI: gitpodAPI}, registry)) baseserver.StartServerForTests(t, srv) diff --git a/components/public-api-server/pkg/server/server.go b/components/public-api-server/pkg/server/server.go index 212649e6c84ee8..f43c4e3fee0679 100644 --- a/components/public-api-server/pkg/server/server.go +++ b/components/public-api-server/pkg/server/server.go @@ -12,21 +12,25 @@ import ( "github.com/gitpod-io/gitpod/public-api-server/pkg/apiv1" "github.com/gitpod-io/gitpod/public-api-server/pkg/proxy" v1 "github.com/gitpod-io/gitpod/public-api/v1" + "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" "net/http" ) func Start(logger *logrus.Entry, cfg Config) error { + registry := prometheus.NewRegistry() + srv, err := baseserver.New("public_api_server", baseserver.WithLogger(logger), baseserver.WithHTTPPort(cfg.HTTPPort), baseserver.WithGRPCPort(cfg.GRPCPort), + baseserver.WithMetricsRegistry(registry), ) if err != nil { return fmt.Errorf("failed to initialize public api server: %w", err) } - if registerErr := register(srv, cfg); registerErr != nil { + if registerErr := register(srv, cfg, registry); registerErr != nil { return fmt.Errorf("failed to register services: %w", registerErr) } @@ -37,7 +41,9 @@ func Start(logger *logrus.Entry, cfg Config) error { return nil } -func register(srv *baseserver.Server, cfg Config) error { +func register(srv *baseserver.Server, cfg Config, registry *prometheus.Registry) error { + proxy.RegisterMetrics(registry) + logger := log.New() m := middleware.NewLoggingMiddleware(logger) srv.HTTPMux().Handle("/", m(http.HandlerFunc(HelloWorldHandler)))