Skip to content

Commit 2428aea

Browse files
committed
[supervisor] add ssh tunnel metrics
1 parent f690f87 commit 2428aea

File tree

4 files changed

+53
-3
lines changed

4 files changed

+53
-3
lines changed

components/supervisor/pkg/metrics/metrics.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
type SupervisorMetrics struct {
1414
IDEReadyDurationTotal *prometheus.HistogramVec
1515
InitializerHistogram *prometheus.HistogramVec
16+
SSHTunnelOpenedTotal *prometheus.CounterVec
17+
SSHTunnelClosedTotal *prometheus.CounterVec
1618
}
1719

1820
func NewMetrics() *SupervisorMetrics {
@@ -27,13 +29,23 @@ func NewMetrics() *SupervisorMetrics {
2729
Help: "initializer speed in bytes per second",
2830
Buckets: prometheus.ExponentialBuckets(1024*1024, 2, 12),
2931
}, []string{"kind"}),
32+
SSHTunnelOpenedTotal: prometheus.NewCounterVec(prometheus.CounterOpts{
33+
Name: "supervisor_ssh_tunnel_opened_total",
34+
Help: "Total number of SSH tunnels opened by the supervisor",
35+
}, []string{}),
36+
SSHTunnelClosedTotal: prometheus.NewCounterVec(prometheus.CounterOpts{
37+
Name: "supervisor_ssh_tunnel_closed_total",
38+
Help: "Total number of SSH tunnels closed by the supervisor",
39+
}, []string{"code"}),
3040
}
3141
}
3242

3343
func (m *SupervisorMetrics) Register(registry *prometheus.Registry) error {
3444
metrics := []prometheus.Collector{
3545
m.IDEReadyDurationTotal,
3646
m.InitializerHistogram,
47+
m.SSHTunnelOpenedTotal,
48+
m.SSHTunnelClosedTotal,
3749
}
3850

3951
for _, metric := range metrics {

components/supervisor/pkg/metrics/reporter.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ func NewGrpcMetricsReporter(gitpodHost string) *GrpcMetricsReporter {
4343
"supervisor_initializer_bytes_second": true,
4444
"supervisor_client_handled_total": true,
4545
"supervisor_client_handling_seconds": true,
46+
"supervisor_ssh_tunnel_opened_total": true,
47+
"supervisor_ssh_tunnel_closed_total": true,
4648
},
4749
values: make(map[string]float64),
4850
addCounter: func(name string, labels map[string]string, value uint64) {

components/supervisor/pkg/supervisor/supervisor.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"os/exec"
2424
"os/signal"
2525
"path/filepath"
26+
"regexp"
2627
"runtime"
2728
"runtime/debug"
2829
"strconv"
@@ -418,7 +419,7 @@ func Run(options ...RunOption) {
418419
}
419420

420421
wg.Add(1)
421-
go startAPIEndpoint(ctx, cfg, &wg, apiServices, tunneledPortsService, metricsReporter, apiEndpointOpts...)
422+
go startAPIEndpoint(ctx, cfg, &wg, apiServices, tunneledPortsService, metricsReporter, supervisorMetrics, apiEndpointOpts...)
422423

423424
wg.Add(1)
424425
go startSSHServer(ctx, cfg, &wg)
@@ -1187,7 +1188,18 @@ func isBlacklistedEnvvar(name string) bool {
11871188
return false
11881189
}
11891190

1190-
func startAPIEndpoint(ctx context.Context, cfg *Config, wg *sync.WaitGroup, services []RegisterableService, tunneled *ports.TunneledPortsService, metricsReporter *metrics.GrpcMetricsReporter, opts ...grpc.ServerOption) {
1191+
var websocketCloseErrorPattern = regexp.MustCompile(`websocket: close (\d+)`)
1192+
1193+
func extractCloseErrorCode(errStr string) string {
1194+
matches := websocketCloseErrorPattern.FindStringSubmatch(errStr)
1195+
if len(matches) < 2 {
1196+
return "unknown"
1197+
}
1198+
1199+
return matches[1]
1200+
}
1201+
1202+
func startAPIEndpoint(ctx context.Context, cfg *Config, wg *sync.WaitGroup, services []RegisterableService, tunneled *ports.TunneledPortsService, metricsReporter *metrics.GrpcMetricsReporter, supervisorMetrics *metrics.SupervisorMetrics, opts ...grpc.ServerOption) {
11911203
defer wg.Done()
11921204
defer log.Debug("startAPIEndpoint shutdown")
11931205

@@ -1308,6 +1320,14 @@ func startAPIEndpoint(ctx context.Context, cfg *Config, wg *sync.WaitGroup, serv
13081320
tunnelOverWebSocket(tunneled, conn)
13091321
}))
13101322
routes.Handle("/_supervisor/tunnel/ssh", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
1323+
supervisorMetrics.SSHTunnelOpenedTotal.WithLabelValues().Inc()
1324+
defer func() {
1325+
code := "unknown"
1326+
if err != nil {
1327+
code = extractCloseErrorCode(err.Error())
1328+
}
1329+
supervisorMetrics.SSHTunnelClosedTotal.WithLabelValues(code).Inc()
1330+
}()
13111331
wsConn, err := upgrader.Upgrade(rw, r, nil)
13121332
if err != nil {
13131333
log.WithError(err).Error("tunnel ssh: upgrade to the WebSocket protocol failed")
@@ -1331,7 +1351,7 @@ func startAPIEndpoint(ctx context.Context, cfg *Config, wg *sync.WaitGroup, serv
13311351

13321352
go io.Copy(conn, conn2)
13331353
_, err = io.Copy(conn2, conn)
1334-
if err != nil && !websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
1354+
if err != nil {
13351355
log.WithError(err).Error("tunnel ssh: error returned from io.copy")
13361356
}
13371357

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,22 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
336336
},
337337
},
338338
},
339+
{
340+
Name: "supervisor_ssh_tunnel_opened_total",
341+
Help: "Total number of SSH tunnels opened by the supervisor",
342+
Labels: []config.LabelAllowList{},
343+
},
344+
{
345+
Name: "supervisor_ssh_tunnel_closed_total",
346+
Help: "Total number of SSH tunnels closed by the supervisor",
347+
Labels: []config.LabelAllowList{
348+
{
349+
Name: "code",
350+
AllowValues: []string{"*"},
351+
DefaultValue: "unknown",
352+
},
353+
},
354+
},
339355
}
340356

341357
histogramMetrics := []config.HistogramMetricsConfiguration{

0 commit comments

Comments
 (0)