Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit5579683

Browse files
committed
Add metrics collector
Signed-off-by: Danny Kopping <dannykopping@gmail.com>
1 parent9676b65 commit5579683

File tree

7 files changed

+484
-24
lines changed

7 files changed

+484
-24
lines changed

‎coderd/prebuilds/api.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55

66
"github.com/google/uuid"
77
"golang.org/x/xerrors"
8+
9+
"github.com/coder/coder/v2/coderd/database"
810
)
911

1012
varErrNoClaimablePrebuiltWorkspaces=xerrors.New("no claimable prebuilt workspaces found")
@@ -25,10 +27,32 @@ type ReconciliationOrchestrator interface {
2527
}
2628

2729
typeReconcilerinterface {
30+
StateSnapshotter
31+
2832
// ReconcileAll orchestrates the reconciliation of all prebuilds across all templates.
2933
// It takes a global snapshot of the system state and then reconciles each preset
3034
// in parallel, creating or deleting prebuilds as needed to reach their desired states.
3135
ReconcileAll(ctx context.Context)error
36+
37+
// ReconcilePreset handles a single PresetSnapshot, determining and executing
38+
// the required actions (creating or deleting prebuilds) based on the current state.
39+
// MUST be called inside a repeatable-read transaction.
40+
ReconcilePreset(ctx context.Context,snapshotPresetSnapshot)error
41+
42+
// CalculateActions determines what actions are needed to reconcile a preset's prebuilds
43+
// to their desired state. This includes creating new prebuilds, deleting excess ones,
44+
// or waiting due to backoff periods.
45+
// MUST be called inside a repeatable-read transaction.
46+
CalculateActions(ctx context.Context,statePresetSnapshot) (*ReconciliationActions,error)
47+
}
48+
49+
// StateSnapshotter defines the operations necessary to capture workspace prebuilds state.
50+
typeStateSnapshotterinterface {
51+
// SnapshotState captures the current state of all prebuilds across templates.
52+
// It creates a global database snapshot that can be viewed as a collection of PresetSnapshots,
53+
// each representing the state of prebuilds for a specific preset.
54+
// MUST be called inside a repeatable-read transaction.
55+
SnapshotState(ctx context.Context,store database.Store) (*GlobalSnapshot,error)
3256
}
3357

3458
typeClaimerinterface {

‎enterprise/coderd/coderd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,6 @@ func (api *API) setupPrebuilds(featureEnabled bool) (agplprebuilds.Reconciliatio
11651165
}
11661166

11671167
reconciler:=prebuilds.NewStoreReconciler(api.Database,api.Pubsub,api.DeploymentValues.Prebuilds,
1168-
api.Logger.Named("prebuilds"),quartz.NewReal())
1168+
api.Logger.Named("prebuilds"),quartz.NewReal(),api.PrometheusRegistry)
11691169
returnreconciler, prebuilds.EnterpriseClaimer{}
11701170
}

‎enterprise/coderd/prebuilds/claim_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"time"
1111

1212
"github.com/google/uuid"
13+
"github.com/prometheus/client_golang/prometheus"
1314
"github.com/stretchr/testify/require"
1415
"golang.org/x/xerrors"
1516

@@ -142,7 +143,7 @@ func TestClaimPrebuild(t *testing.T) {
142143
EntitlementsUpdateInterval:time.Second,
143144
})
144145

145-
reconciler:=prebuilds.NewStoreReconciler(spy,pubsub, codersdk.PrebuildsConfig{},logger,quartz.NewMock(t))
146+
reconciler:=prebuilds.NewStoreReconciler(spy,pubsub, codersdk.PrebuildsConfig{},logger,quartz.NewMock(t),prometheus.NewRegistry())
146147
varclaimer agplprebuilds.Claimer=prebuilds.NewEnterpriseClaimer(spy)
147148
api.AGPL.PrebuildsClaimer.Store(&claimer)
148149

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package prebuilds
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
"cdr.dev/slog"
8+
9+
"github.com/prometheus/client_golang/prometheus"
10+
11+
"github.com/coder/coder/v2/coderd/database"
12+
"github.com/coder/coder/v2/coderd/database/dbauthz"
13+
"github.com/coder/coder/v2/coderd/prebuilds"
14+
)
15+
16+
var (
17+
labels= []string{"template_name","preset_name","organization_name"}
18+
createdPrebuildsDesc=prometheus.NewDesc(
19+
"coderd_prebuilds_created_total",
20+
"The number of prebuilds that have been created to meet the desired count set by presets.",
21+
labels,
22+
nil,
23+
)
24+
failedPrebuildsDesc=prometheus.NewDesc(
25+
"coderd_prebuilds_failed_total",
26+
"The number of prebuilds that failed to build during creation.",
27+
labels,
28+
nil,
29+
)
30+
claimedPrebuildsDesc=prometheus.NewDesc(
31+
"coderd_prebuilds_claimed_total",
32+
"The number of prebuilds that were claimed by a user. Each count means that a user created a workspace using a preset and was assigned a prebuild instead of a brand new workspace.",
33+
labels,
34+
nil,
35+
)
36+
usedPresetsDesc=prometheus.NewDesc(
37+
"coderd_prebuilds_used_presets",
38+
"The number of times a preset was used to build a prebuild.",
39+
labels,
40+
nil,
41+
)
42+
desiredPrebuildsDesc=prometheus.NewDesc(
43+
"coderd_prebuilds_desired",
44+
"The number of prebuilds desired by each preset of each template.",
45+
labels,
46+
nil,
47+
)
48+
runningPrebuildsDesc=prometheus.NewDesc(
49+
"coderd_prebuilds_running",
50+
"The number of prebuilds that are currently running. Running prebuilds have successfully started, but they may not be ready to be claimed by a user yet.",
51+
labels,
52+
nil,
53+
)
54+
eligiblePrebuildsDesc=prometheus.NewDesc(
55+
"coderd_prebuilds_eligible",
56+
"The number of eligible prebuilds. Eligible prebuilds are prebuilds that are ready to be claimed by a user.",
57+
labels,
58+
nil,
59+
)
60+
)
61+
62+
typeMetricsCollectorstruct {
63+
database database.Store
64+
logger slog.Logger
65+
snapshotter prebuilds.StateSnapshotter
66+
}
67+
68+
var_ prometheus.Collector=new(MetricsCollector)
69+
70+
funcNewMetricsCollector(db database.Store,logger slog.Logger,snapshotter prebuilds.StateSnapshotter)*MetricsCollector {
71+
return&MetricsCollector{
72+
database:db,
73+
logger:logger.Named("prebuilds_metrics_collector"),
74+
snapshotter:snapshotter,
75+
}
76+
}
77+
78+
func (*MetricsCollector)Describe(descChchan<-*prometheus.Desc) {
79+
descCh<-createdPrebuildsDesc
80+
descCh<-failedPrebuildsDesc
81+
descCh<-claimedPrebuildsDesc
82+
descCh<-usedPresetsDesc
83+
descCh<-desiredPrebuildsDesc
84+
descCh<-runningPrebuildsDesc
85+
descCh<-eligiblePrebuildsDesc
86+
}
87+
88+
func (mc*MetricsCollector)Collect(metricsChchan<- prometheus.Metric) {
89+
ctx,cancel:=context.WithTimeout(dbauthz.AsPrebuildsOrchestrator(context.Background()),10*time.Second)
90+
defercancel()
91+
// nolint:gocritic // just until we get back to this
92+
prebuildMetrics,err:=mc.database.GetPrebuildMetrics(ctx)
93+
iferr!=nil {
94+
mc.logger.Error(ctx,"failed to get prebuild metrics",slog.Error(err))
95+
return
96+
}
97+
98+
for_,metric:=rangeprebuildMetrics {
99+
metricsCh<-prometheus.MustNewConstMetric(createdPrebuildsDesc,prometheus.CounterValue,float64(metric.CreatedCount),metric.TemplateName,metric.PresetName,metric.OrganizationName)
100+
metricsCh<-prometheus.MustNewConstMetric(failedPrebuildsDesc,prometheus.CounterValue,float64(metric.FailedCount),metric.TemplateName,metric.PresetName,metric.OrganizationName)
101+
metricsCh<-prometheus.MustNewConstMetric(claimedPrebuildsDesc,prometheus.CounterValue,float64(metric.ClaimedCount),metric.TemplateName,metric.PresetName,metric.OrganizationName)
102+
}
103+
104+
snapshot,err:=mc.snapshotter.SnapshotState(ctx,mc.database)
105+
iferr!=nil {
106+
mc.logger.Error(ctx,"failed to get latest prebuild state",slog.Error(err))
107+
return
108+
}
109+
110+
for_,preset:=rangesnapshot.Presets {
111+
if!preset.UsingActiveVersion {
112+
continue
113+
}
114+
115+
presetSnapshot,err:=snapshot.FilterByPreset(preset.ID)
116+
iferr!=nil {
117+
mc.logger.Error(ctx,"failed to filter by preset",slog.Error(err))
118+
continue
119+
}
120+
state:=presetSnapshot.CalculateState()
121+
122+
metricsCh<-prometheus.MustNewConstMetric(desiredPrebuildsDesc,prometheus.GaugeValue,float64(state.Desired),preset.TemplateName,preset.Name,preset.OrganizationName)
123+
metricsCh<-prometheus.MustNewConstMetric(runningPrebuildsDesc,prometheus.GaugeValue,float64(state.Actual),preset.TemplateName,preset.Name,preset.OrganizationName)
124+
metricsCh<-prometheus.MustNewConstMetric(eligiblePrebuildsDesc,prometheus.GaugeValue,float64(state.Eligible),preset.TemplateName,preset.Name,preset.OrganizationName)
125+
}
126+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp