Skip to content

Commit 198d71d

Browse files
committed
Add metric
1 parent e1dcb63 commit 198d71d

File tree

12 files changed

+130
-21
lines changed

12 files changed

+130
-21
lines changed

components/common-go/experiments/types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ func WithGitpodProxy(gitpodHost string) ClientOpt {
4949
}
5050
}
5151

52+
func WithPollInterval(interval time.Duration) ClientOpt {
53+
return func(o *options) {
54+
o.pollInterval = interval
55+
}
56+
}
57+
5258
func WithDefaultClient(defaultClient Client) ClientOpt {
5359
return func(o *options) {
5460
o.defaultClient = defaultClient

components/service-waiter/cmd/component.go

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package cmd
77
import (
88
"context"
99
"fmt"
10+
"strconv"
1011
"time"
1112

1213
"github.com/sirupsen/logrus"
@@ -15,17 +16,20 @@ import (
1516

1617
"github.com/gitpod-io/gitpod/common-go/experiments"
1718
"github.com/gitpod-io/gitpod/common-go/log"
19+
"github.com/gitpod-io/gitpod/service-waiter/pkg/metrics"
1820
corev1 "k8s.io/api/core/v1"
1921
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2022
"k8s.io/client-go/kubernetes"
2123
"k8s.io/client-go/rest"
2224
)
2325

2426
var componentCmdOpt struct {
25-
image string
26-
namespace string
27-
component string
28-
labels string
27+
image string
28+
namespace string
29+
component string
30+
labels string
31+
ideMetricsHost string
32+
gitpodHost string
2933

3034
featureFlagTimeout time.Duration
3135
}
@@ -138,7 +142,9 @@ func init() {
138142
componentCmd.Flags().StringVar(&componentCmdOpt.namespace, "namespace", "", "The namespace of deployment")
139143
componentCmd.Flags().StringVar(&componentCmdOpt.component, "component", "", "Component name of deployment")
140144
componentCmd.Flags().StringVar(&componentCmdOpt.labels, "labels", "", "Labels of deployment")
145+
componentCmd.Flags().StringVar(&componentCmdOpt.ideMetricsHost, "ide-metrics-host", "", "Host of ide metrics")
141146
componentCmd.Flags().DurationVar(&componentCmdOpt.featureFlagTimeout, "feature-flag-timeout", 3*time.Minute, "The maximum time to wait for feature flag")
147+
componentCmd.Flags().StringVar(&componentCmdOpt.gitpodHost, "gitpod-host", "", "Domain of Gitpod installation")
142148

143149
_ = componentCmd.MarkFlagRequired("namespace")
144150
_ = componentCmd.MarkFlagRequired("component")
@@ -148,18 +154,26 @@ func init() {
148154
func startWaitFeatureFlag(ctx context.Context, timeout time.Duration) {
149155
featureFlagCtx, cancel := context.WithTimeout(ctx, timeout)
150156
defer cancel()
151-
client := experiments.NewClient(experiments.WithDefaultClient(nil))
157+
client := experiments.NewClient(experiments.WithDefaultClient(nil), experiments.WithPollInterval(time.Second*3))
152158
defaultSkip := true
153159
if client == nil {
154160
log.Error("failed to create experiments client, skip immediately")
155161
shouldSkipComponentWaiter = defaultSkip
162+
metrics.AddSkipComponentsCounter(componentCmdOpt.ideMetricsHost, strconv.FormatBool(shouldSkipComponentWaiter), false)
156163
return
157164
}
158-
startTime := time.Now()
159-
value, isActualValue, fetchTimes := ActualWaitFeatureFlag(featureFlagCtx, client, defaultSkip)
160-
avgTime := time.Since(startTime) / time.Duration(fetchTimes)
161-
log.WithField("fetchTimes", fetchTimes).WithField("avgTime", avgTime).WithField("isActualValue", isActualValue).WithField("value", value).Info("get final value of feature flag")
162-
shouldSkipComponentWaiter = value
165+
getShouldSkipComponentWaiter := func() {
166+
startTime := time.Now()
167+
value, isActualValue, fetchTimes := ActualWaitFeatureFlag(featureFlagCtx, client, defaultSkip)
168+
avgTime := time.Since(startTime) / time.Duration(fetchTimes)
169+
log.WithField("fetchTimes", fetchTimes).WithField("avgTime", avgTime).WithField("isActualValue", isActualValue).WithField("value", value).Info("get final value of feature flag")
170+
shouldSkipComponentWaiter = value
171+
metrics.AddSkipComponentsCounter(componentCmdOpt.ideMetricsHost, strconv.FormatBool(shouldSkipComponentWaiter), isActualValue)
172+
}
173+
for !shouldSkipComponentWaiter {
174+
getShouldSkipComponentWaiter()
175+
time.Sleep(1 * time.Second)
176+
}
163177
}
164178

165179
var FeatureSleepDuration = 1 * time.Second
@@ -175,7 +189,8 @@ func ActualWaitFeatureFlag(ctx context.Context, client experiments.Client, defau
175189
return defaultValue, false, fetchTimes
176190
default:
177191
stringValue := client.GetStringValue(ctx, experiments.ServiceWaiterSkipComponentsFlag, "NONE", experiments.Attributes{
178-
Component: componentCmdOpt.component,
192+
GitpodHost: componentCmdOpt.gitpodHost,
193+
Component: componentCmdOpt.component,
179194
})
180195
fetchTimes++
181196
if stringValue == "true" {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright (c) 2023 Gitpod GmbH. All rights reserved.
2+
// Licensed under the GNU Affero General Public License (AGPL).
3+
// See License.AGPL.txt in the project root for license information.
4+
5+
package metrics
6+
7+
import (
8+
"bytes"
9+
"encoding/json"
10+
"net/http"
11+
"strconv"
12+
13+
"github.com/gitpod-io/gitpod/common-go/log"
14+
)
15+
16+
// service_waiter_skip_components
17+
const WaitComponentFeatureFlagMetricName = "service_waiter_skip_components_result_total"
18+
19+
func AddSkipComponentsCounter(host, value string, isActual bool) {
20+
labels := map[string]string{
21+
"value": value,
22+
"ok": strconv.FormatBool(isActual),
23+
}
24+
addCounter(host, WaitComponentFeatureFlagMetricName, labels)
25+
}
26+
27+
func addCounter(host, metricName string, labels map[string]string) {
28+
if host == "" {
29+
log.Error("host is empty")
30+
return
31+
}
32+
body := map[string]interface{}{
33+
"labels": labels,
34+
"value": 1,
35+
}
36+
b, err := json.Marshal(body)
37+
if err != nil {
38+
log.WithError(err).Error("cannot marshal body")
39+
return
40+
}
41+
resp, err := http.Post(host+"/metrics-api/metrics/counter/add/"+metricName, "application/json", bytes.NewReader(b))
42+
if err != nil {
43+
log.WithError(err).Error("cannot post metrics")
44+
return
45+
}
46+
defer resp.Body.Close()
47+
if resp.StatusCode != http.StatusOK {
48+
log.WithField("status", resp.Status).Error("failed to post metrics")
49+
}
50+
log.Info("metric reported")
51+
}

install/installer/pkg/common/common.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,6 @@ func RedisWaiterContainer(ctx *RenderContext) *corev1.Container {
512512
// ServerComponentWaiterContainer is the container used to wait for the deployment/server to be ready
513513
// it requires
514514
// - pods list access to the cluster
515-
// - configcat env
516515
func ServerComponentWaiterContainer(ctx *RenderContext) *corev1.Container {
517516
image := ctx.ImageName(ctx.Config.Repository, ServerComponent, ctx.VersionManifest.Components.Server.Version)
518517
return componentWaiterContainer(ctx, ServerComponent, DefaultLabelSelector(ServerComponent), image)
@@ -521,7 +520,6 @@ func ServerComponentWaiterContainer(ctx *RenderContext) *corev1.Container {
521520
// PublicApiServerComponentWaiterContainer is the container used to wait for the deployment/public-api-server to be ready
522521
// it requires
523522
// - pods list access to the cluster
524-
// - configcat env
525523
func PublicApiServerComponentWaiterContainer(ctx *RenderContext) *corev1.Container {
526524
image := ctx.ImageName(ctx.Config.Repository, PublicApiComponent, ctx.VersionManifest.Components.PublicAPIServer.Version)
527525
return componentWaiterContainer(ctx, PublicApiComponent, DefaultLabelSelector(PublicApiComponent), image)
@@ -534,6 +532,10 @@ func componentWaiterContainer(ctx *RenderContext, component, labels, image strin
534532
Args: []string{
535533
"-v",
536534
"component",
535+
"--gitpod-host",
536+
ctx.Config.Domain,
537+
"--ide-metrics-host",
538+
"http://" + IDEMetricsComponent + ":" + strconv.Itoa(IDEMetricsPort),
537539
"--namespace",
538540
ctx.Namespace,
539541
"--component",
@@ -548,6 +550,7 @@ func componentWaiterContainer(ctx *RenderContext, component, labels, image strin
548550
AllowPrivilegeEscalation: pointer.Bool(false),
549551
RunAsUser: pointer.Int64(31001),
550552
},
553+
Env: ConfigcatEnv(ctx),
551554
}
552555
}
553556

install/installer/pkg/common/common_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package common_test
66

77
import (
88
"fmt"
9+
"strconv"
910
"testing"
1011

1112
"github.com/gitpod-io/gitpod/common-go/baseserver"
@@ -58,7 +59,8 @@ func TestPublicApiServerComponentWaiterContainer(t *testing.T) {
5859
container := common.PublicApiServerComponentWaiterContainer(ctx)
5960
labels := common.DefaultLabelSelector(common.PublicApiComponent)
6061
require.Equal(t, labels, "app=gitpod,component=public-api-server")
61-
require.Equal(t, []string{"-v", "component", "--namespace", "test_namespace", "--component", common.PublicApiComponent, "--labels", labels, "--image", ctx.Config.Repository + "/public-api-server:" + "happy_path_papi_image"}, container.Args)
62+
ideMetricsHost := "http://" + common.IDEMetricsComponent + ":" + strconv.Itoa(common.IDEMetricsPort)
63+
require.Equal(t, []string{"-v", "component", "--gitpod-host", ctx.Config.Domain, "--ide-metrics-host", ideMetricsHost, "--namespace", "test_namespace", "--component", common.PublicApiComponent, "--labels", labels, "--image", ctx.Config.Repository + "/public-api-server:" + "happy_path_papi_image"}, container.Args)
6264
}
6365

6466
func TestServerComponentWaiterContainer(t *testing.T) {
@@ -71,5 +73,6 @@ func TestServerComponentWaiterContainer(t *testing.T) {
7173
container := common.ServerComponentWaiterContainer(ctx)
7274
labels := common.DefaultLabelSelector(common.ServerComponent)
7375
require.Equal(t, labels, "app=gitpod,component=server")
74-
require.Equal(t, []string{"-v", "component", "--namespace", "test_namespace", "--component", common.ServerComponent, "--labels", labels, "--image", ctx.Config.Repository + "/server:" + "happy_path_server_image"}, container.Args)
76+
ideMetricsHost := "http://" + common.IDEMetricsComponent + ":" + strconv.Itoa(common.IDEMetricsPort)
77+
require.Equal(t, []string{"-v", "component", "--gitpod-host", ctx.Config.Domain, "--ide-metrics-host", ideMetricsHost, "--namespace", "test_namespace", "--component", common.ServerComponent, "--labels", labels, "--image", ctx.Config.Repository + "/server:" + "happy_path_server_image"}, container.Args)
7578
}

install/installer/pkg/common/constants.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ const (
6262
AuthPKISecretName = "auth-pki"
6363
IDEServiceComponent = "ide-service"
6464
OpenVSXProxyComponent = "openvsx-proxy"
65+
DashboardComponent = "dashboard"
66+
IDEMetricsComponent = "ide-metrics"
67+
IDEMetricsPort = 3000
6568
)
6669

6770
var (

install/installer/pkg/components/dashboard/constants.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
package dashboard
66

7+
import "github.com/gitpod-io/gitpod/installer/pkg/common"
8+
79
const (
8-
Component = "dashboard"
10+
Component = common.DashboardComponent
911
ContainerPort = 80
1012
PortName = "http"
1113
ServicePort = 3001

install/installer/pkg/components/dashboard/deployment.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) {
7272
},
7373
Env: common.CustomizeEnvvar(ctx, Component, common.MergeEnv(
7474
common.DefaultEnv(&ctx.Config),
75-
common.ConfigcatEnv(ctx),
7675
)),
7776
ReadinessProbe: &corev1.Probe{
7877
ProbeHandler: corev1.ProbeHandler{

install/installer/pkg/components/ide-metrics/configmap.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,23 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
352352
},
353353
},
354354
},
355+
{
356+
Name: "service_waiter_skip_components_result_total",
357+
Help: "Total number of wait result of service_waiter/component service_waiter_skip_components flag",
358+
Labels: []config.LabelAllowList{
359+
{
360+
Name: "value",
361+
// possible values "true", "false"
362+
AllowValues: []string{"*"},
363+
DefaultValue: "NONE",
364+
},
365+
{
366+
Name: "ok",
367+
AllowValues: []string{"true", "false"},
368+
DefaultValue: "false",
369+
},
370+
},
371+
},
355372
}
356373

357374
histogramMetrics := []config.HistogramMetricsConfiguration{

install/installer/pkg/components/ide-metrics/constants.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
package ide_metrics
66

7+
import "github.com/gitpod-io/gitpod/installer/pkg/common"
8+
79
const (
8-
Component = "ide-metrics"
9-
ContainerPort = 3000
10+
Component = common.IDEMetricsComponent
11+
ContainerPort = common.IDEMetricsPort
1012
PortName = "http"
11-
ServicePort = 3000
12-
ReadinessPort = 3000
13+
ServicePort = common.IDEMetricsPort
14+
ReadinessPort = common.IDEMetricsPort
1315
VolumeConfig = "config"
1416
)

install/installer/pkg/components/ide-metrics/networkpolicy.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ func networkpolicy(ctx *common.RenderContext) ([]runtime.Object, error) {
4141
PodSelector: &metav1.LabelSelector{MatchLabels: map[string]string{
4242
"component": ideproxy.Component,
4343
}},
44+
}, {
45+
PodSelector: &metav1.LabelSelector{MatchLabels: map[string]string{
46+
"component": common.DashboardComponent,
47+
}},
4448
}},
4549
}},
4650
},

install/installer/pkg/components/proxy/networkpolicy.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ func networkpolicy(ctx *common.RenderContext) ([]runtime.Object, error) {
100100
PodSelector: &metav1.LabelSelector{MatchLabels: map[string]string{
101101
"component": common.OpenVSXProxyComponent,
102102
}},
103+
}, {
104+
PodSelector: &metav1.LabelSelector{MatchLabels: map[string]string{
105+
"component": common.DashboardComponent,
106+
}},
103107
}},
104108
}},
105109
},

0 commit comments

Comments
 (0)