@@ -2,6 +2,7 @@ package prebuilds
2
2
3
3
import (
4
4
"context"
5
+ "fmt"
5
6
"sync/atomic"
6
7
"time"
7
8
@@ -11,7 +12,6 @@ import (
11
12
"cdr.dev/slog"
12
13
13
14
"github.com/coder/coder/v2/coderd/database"
14
- "github.com/coder/coder/v2/coderd/database/dbauthz"
15
15
"github.com/coder/coder/v2/coderd/prebuilds"
16
16
)
17
17
57
57
labels ,
58
58
nil ,
59
59
)
60
+ lastUpdateDesc = prometheus .NewDesc (
61
+ "coderd_prebuilt_workspaces_metrics_last_updated" ,
62
+ "The unix timestamp when the metrics related to prebuilt workspaces were last updated; these metrics are cached." ,
63
+ []string {},
64
+ nil ,
65
+ )
60
66
)
61
67
62
68
const (
@@ -91,18 +97,16 @@ func (*MetricsCollector) Describe(descCh chan<- *prometheus.Desc) {
91
97
descCh <- desiredPrebuildsDesc
92
98
descCh <- runningPrebuildsDesc
93
99
descCh <- eligiblePrebuildsDesc
100
+ descCh <- lastUpdateDesc
94
101
}
95
102
96
103
// Collect uses the cached state to set configured metrics.
97
104
// The state is cached because this function can be called multiple times per second and retrieving the current state
98
105
// is an expensive operation.
99
106
func (mc * MetricsCollector ) Collect (metricsCh chan <- prometheus.Metric ) {
100
- // nolint:gocritic // We need to set an authz context to read metrics from the db.
101
- ctx := dbauthz .AsPrebuildsOrchestrator (context .Background ())
102
-
103
- currentState := mc .latestState .Load ()
107
+ currentState := mc .latestState .Load () // Grab a copy; it's ok if it goes stale during the course of this func.
104
108
if currentState == nil {
105
- mc .logger .Warn (ctx , "failed to set prebuilds metrics; state not set" )
109
+ mc .logger .Warn (context . Background () , "failed to set prebuilds metrics; state not set" )
106
110
return
107
111
}
108
112
@@ -119,7 +123,7 @@ func (mc *MetricsCollector) Collect(metricsCh chan<- prometheus.Metric) {
119
123
120
124
presetSnapshot , err := currentState .snapshot .FilterByPreset (preset .ID )
121
125
if err != nil {
122
- mc .logger .Error (ctx , "failed to filter by preset" , slog .Error (err ))
126
+ mc .logger .Error (context . Background () , "failed to filter by preset" , slog .Error (err ))
123
127
continue
124
128
}
125
129
state := presetSnapshot .CalculateState ()
@@ -128,11 +132,14 @@ func (mc *MetricsCollector) Collect(metricsCh chan<- prometheus.Metric) {
128
132
metricsCh <- prometheus .MustNewConstMetric (runningPrebuildsDesc , prometheus .GaugeValue , float64 (state .Actual ), preset .TemplateName , preset .Name , preset .OrganizationName )
129
133
metricsCh <- prometheus .MustNewConstMetric (eligiblePrebuildsDesc , prometheus .GaugeValue , float64 (state .Eligible ), preset .TemplateName , preset .Name , preset .OrganizationName )
130
134
}
135
+
136
+ metricsCh <- prometheus .MustNewConstMetric (lastUpdateDesc , prometheus .GaugeValue , float64 (currentState .createdAt .Unix ()))
131
137
}
132
138
133
139
type state struct {
134
140
prebuildMetrics []database.GetPrebuildMetricsRow
135
141
snapshot * prebuilds.GlobalSnapshot
142
+ createdAt time.Time
136
143
}
137
144
138
145
// BackgroundFetch updates the metrics state every given interval.
@@ -157,6 +164,7 @@ func (mc *MetricsCollector) BackgroundFetch(ctx context.Context, updateInterval,
157
164
158
165
// UpdateState builds the current metrics state.
159
166
func (mc * MetricsCollector ) UpdateState (ctx context.Context , timeout time.Duration ) error {
167
+ start := time .Now ()
160
168
mc .logger .Debug (ctx , "fetching prebuilds metrics state" )
161
169
fetchCtx , fetchCancel := context .WithTimeout (ctx , timeout )
162
170
defer fetchCancel ()
@@ -170,11 +178,12 @@ func (mc *MetricsCollector) UpdateState(ctx context.Context, timeout time.Durati
170
178
if err != nil {
171
179
return xerrors .Errorf ("snapshot state: %w" , err )
172
180
}
173
- mc .logger .Debug (ctx , "fetched prebuilds metrics state" )
181
+ mc .logger .Debug (ctx , "fetched prebuilds metrics state" , slog . F ( "duration_secs" , fmt . Sprintf ( "%.2f" , time . Since ( start ). Seconds ())) )
174
182
175
183
mc .latestState .Store (& state {
176
184
prebuildMetrics : prebuildMetrics ,
177
185
snapshot : snapshot ,
186
+ createdAt : time .Now (),
178
187
})
179
188
return nil
180
189
}
0 commit comments