Files
coder/coderd/wsbuilder/metrics.go
T
Callum Styan 5f3be6b288 feat: add provisioner job queue wait time histogram and jobs enqueued counter (#21869)
This PR adds some metrics to help identify job enqueue rates and
latencies. This work was initiated as a way to help reduce the cost of
the observation/measurement itself for autostart scaletests, which
impacts our ability to identify/reason about the load caused by
autostart. See: https://github.com/coder/internal/issues/1209

I've extended the metrics here to account for regular user initiated
builds, prebuilds, autostarts, etc. IMO there is still the question here
of whether we want to include or need the `transition` label, which is
only present on workspace builds. Including it does lead to an increase
in cardinality, and in the case of the histogram (when not using native
histograms) that's at least a few extra series for every bucket. We
could remove the transition label there but keep it on the counter.

Additionally, the histogram is currently observing latencies for other
jobs, such as template builds/version imports, those do not have a
transition type associated with them.

Tested briefly in a workspace, can see metric values like the following:
-
`coderd_workspace_builds_enqueued_total{build_reason="autostart",provisioner_type="terraform",status="success",transition="start"}
1`
-
`coderd_provisioner_job_queue_wait_seconds_bucket{build_reason="autostart",job_type="workspace_build",provisioner_type="terraform",transition="start",le="0.025"}
1`

---------

Signed-off-by: Callum Styan <callumstyan@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 13:40:47 -08:00

43 lines
1.2 KiB
Go

package wsbuilder
import "github.com/prometheus/client_golang/prometheus"
// Metrics holds metrics related to workspace build creation.
type Metrics struct {
workspaceBuildsEnqueued *prometheus.CounterVec
}
// Metric label values for build status.
const (
BuildStatusSuccess = "success"
BuildStatusFailed = "failed"
)
func NewMetrics(reg prometheus.Registerer) (*Metrics, error) {
m := &Metrics{
workspaceBuildsEnqueued: prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "coderd",
Name: "workspace_builds_enqueued_total",
Help: "Total number of workspace build enqueue attempts.",
}, []string{"provisioner_type", "build_reason", "transition", "status"}),
}
if reg != nil {
if err := reg.Register(m.workspaceBuildsEnqueued); err != nil {
return nil, err
}
}
return m, nil
}
// RecordBuildEnqueued records a workspace build enqueue attempt. It determines
// the status based on whether an error occurred and increments the counter.
func (m *Metrics) RecordBuildEnqueued(provisionerType, buildReason, transition string, err error) {
status := BuildStatusSuccess
if err != nil {
status = BuildStatusFailed
}
m.workspaceBuildsEnqueued.WithLabelValues(provisionerType, buildReason, transition, status).Inc()
}