Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/ws-manager-bridge/src/metrics.ts
2498 views
1
/**
2
* Copyright (c) 2020 Gitpod GmbH. All rights reserved.
3
* Licensed under the GNU Affero General Public License (AGPL).
4
* See License.AGPL.txt in the project root for license information.
5
*/
6
7
import * as prom from "prom-client";
8
import { injectable } from "inversify";
9
import { WorkspaceInstance } from "@gitpod/gitpod-protocol";
10
import { WorkspaceClusterWoTLS } from "@gitpod/gitpod-protocol/lib/workspace-cluster";
11
import { WorkspaceType } from "@gitpod/gitpod-protocol";
12
13
@injectable()
14
export class Metrics {
15
protected readonly workspaceStartupTimeHistogram: prom.Histogram<string>;
16
protected readonly timeToFirstUserActivityHistogram: prom.Histogram<string>;
17
protected readonly clusterScore: prom.Gauge<string>;
18
protected readonly clusterCordoned: prom.Gauge<string>;
19
protected readonly statusUpdatesTotal: prom.Counter<string>;
20
protected readonly staleStatusUpdatesTotal: prom.Counter<string>;
21
protected readonly stalePrebuildEventsTotal: prom.Counter<string>;
22
protected readonly prebuildsCompletedTotal: prom.Counter<string>;
23
protected readonly instanceMarkedStoppedTotal: prom.Counter<string>;
24
25
protected readonly workspaceInstanceUpdateStartedTotal: prom.Counter<string>;
26
protected readonly workspaceInstanceUpdateCompletedSeconds: prom.Histogram<string>;
27
28
protected readonly updatesPublishedTotal: prom.Counter<string>;
29
30
protected activeClusterNames = new Set<string>();
31
32
constructor() {
33
this.workspaceStartupTimeHistogram = new prom.Histogram({
34
name: "workspace_startup_time",
35
help: "The time until a workspace instance is marked running",
36
labelNames: ["neededImageBuild", "region"],
37
buckets: prom.exponentialBuckets(2, 2, 10),
38
});
39
this.timeToFirstUserActivityHistogram = new prom.Histogram({
40
name: "first_user_activity_time",
41
help: "The time between a workspace is running and first user activity",
42
labelNames: ["region"],
43
buckets: prom.exponentialBuckets(2, 2, 10),
44
});
45
this.clusterScore = new prom.Gauge({
46
name: "gitpod_ws_manager_bridge_cluster_score",
47
help: "Score of the individual registered workspace cluster",
48
labelNames: ["workspace_cluster"],
49
});
50
this.clusterCordoned = new prom.Gauge({
51
name: "gitpod_ws_manager_bridge_cluster_cordoned",
52
help: "Cordoned status of the individual registered workspace cluster",
53
labelNames: ["workspace_cluster"],
54
});
55
this.statusUpdatesTotal = new prom.Counter({
56
name: "gitpod_ws_manager_bridge_status_updates_total",
57
help: "Total workspace status updates received",
58
labelNames: ["workspace_cluster", "known_instance"],
59
});
60
this.staleStatusUpdatesTotal = new prom.Counter({
61
name: "gitpod_ws_manager_bridge_stale_status_updates_total",
62
help: "Total count of stale status updates received by workspace manager bridge",
63
});
64
this.stalePrebuildEventsTotal = new prom.Counter({
65
name: "gitpod_ws_manager_bridge_stale_prebuild_events_total",
66
help: "Total count of stale prebuild events received by workspace manager bridge",
67
});
68
69
this.workspaceInstanceUpdateStartedTotal = new prom.Counter({
70
name: "gitpod_ws_manager_bridge_workspace_instance_update_started_total",
71
help: "Total number of workspace instance updates that started processing",
72
labelNames: ["workspace_cluster", "workspace_instance_type"],
73
});
74
75
this.workspaceInstanceUpdateCompletedSeconds = new prom.Histogram({
76
name: "gitpod_ws_manager_bridge_workspace_instance_update_completed_seconds",
77
help: "Histogram of completed workspace instance updates, by outcome",
78
labelNames: ["workspace_cluster", "workspace_instance_type", "outcome"],
79
buckets: prom.exponentialBuckets(0.05, 2, 8),
80
});
81
82
this.prebuildsCompletedTotal = new prom.Counter({
83
name: "gitpod_prebuilds_completed_total",
84
help: "Counter of total prebuilds ended.",
85
labelNames: ["state"],
86
});
87
88
this.instanceMarkedStoppedTotal = new prom.Counter({
89
name: "gitpod_ws_instances_marked_stopped_total",
90
help: "Counter of total instances marked stopped by the ws-manager-bridge",
91
labelNames: ["previous_phase"],
92
});
93
}
94
95
observeWorkspaceStartupTime(instance: WorkspaceInstance): void {
96
const timeToRunningSecs =
97
(new Date(instance.startedTime!).getTime() - new Date(instance.creationTime).getTime()) / 1000;
98
this.workspaceStartupTimeHistogram.observe(
99
{
100
neededImageBuild: JSON.stringify(instance.status.conditions.neededImageBuild),
101
region: instance.region,
102
},
103
timeToRunningSecs,
104
);
105
}
106
107
observeFirstUserActivity(instance: WorkspaceInstance, firstUserActivity: string): void {
108
if (!instance.startedTime) {
109
return;
110
}
111
112
const timeToFirstUserActivity =
113
(new Date(firstUserActivity).getTime() - new Date(instance.startedTime!).getTime()) / 1000;
114
this.timeToFirstUserActivityHistogram.observe(
115
{
116
region: instance.region,
117
},
118
timeToFirstUserActivity,
119
);
120
}
121
122
updateClusterMetrics(clusters: WorkspaceClusterWoTLS[]): void {
123
const newActiveClusterNames = new Set<string>();
124
clusters.forEach((cluster) => {
125
this.clusterCordoned.labels(cluster.name).set(cluster.state === "cordoned" ? 1 : 0);
126
this.clusterScore.labels(cluster.name).set(cluster.score);
127
newActiveClusterNames.add(cluster.name);
128
});
129
130
const noLongerActiveCluster = Array.from(this.activeClusterNames).filter((c) => !newActiveClusterNames.has(c));
131
noLongerActiveCluster.forEach((clusterName) => {
132
this.clusterCordoned.remove(clusterName);
133
this.clusterScore.remove(clusterName);
134
});
135
this.activeClusterNames = newActiveClusterNames;
136
}
137
138
statusUpdateReceived(installation: string, knownInstance: boolean): void {
139
this.statusUpdatesTotal.labels(installation, knownInstance ? "true" : "false").inc();
140
}
141
142
recordStaleStatusUpdate(): void {
143
this.staleStatusUpdatesTotal.inc();
144
}
145
146
recordStalePrebuildEvent(): void {
147
this.stalePrebuildEventsTotal.inc();
148
}
149
150
reportWorkspaceInstanceUpdateStarted(workspaceCluster: string, type: WorkspaceType): void {
151
this.workspaceInstanceUpdateStartedTotal.labels(workspaceCluster, type).inc();
152
}
153
154
reportWorkspaceInstanceUpdateCompleted(
155
durationSeconds: number,
156
workspaceCluster: string,
157
type: WorkspaceType,
158
skippedUpdate: boolean,
159
error?: Error,
160
): void {
161
const outcome = skippedUpdate ? "skipped" : error ? "error" : "success";
162
this.workspaceInstanceUpdateCompletedSeconds.labels(workspaceCluster, type, outcome).observe(durationSeconds);
163
}
164
165
increasePrebuildsCompletedCounter(state: string) {
166
this.prebuildsCompletedTotal.inc({ state });
167
}
168
169
increaseInstanceMarkedStoppedCounter(previous_phase: string) {
170
this.instanceMarkedStoppedTotal.inc({ previous_phase });
171
}
172
}
173
174