mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
This adds workspace totals indexed by status. It could be any codersdk.ProvisionerJobStatus.
107 lines
2.7 KiB
Go
107 lines
2.7 KiB
Go
package prometheusmetrics
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
|
|
"github.com/coder/coder/coderd"
|
|
"github.com/coder/coder/coderd/database"
|
|
)
|
|
|
|
// ActiveUsers tracks the number of users that have authenticated within the past hour.
|
|
func ActiveUsers(ctx context.Context, registerer prometheus.Registerer, db database.Store, duration time.Duration) (context.CancelFunc, error) {
|
|
if duration == 0 {
|
|
duration = 5 * time.Minute
|
|
}
|
|
|
|
gauge := prometheus.NewGauge(prometheus.GaugeOpts{
|
|
Namespace: "coderd",
|
|
Subsystem: "api",
|
|
Name: "active_users_duration_hour",
|
|
Help: "The number of users that have been active within the last hour.",
|
|
})
|
|
err := registerer.Register(gauge)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ctx, cancelFunc := context.WithCancel(ctx)
|
|
ticker := time.NewTicker(duration)
|
|
go func() {
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
}
|
|
apiKeys, err := db.GetAPIKeysLastUsedAfter(ctx, database.Now().Add(-1*time.Hour))
|
|
if err != nil {
|
|
continue
|
|
}
|
|
distinctUsers := map[uuid.UUID]struct{}{}
|
|
for _, apiKey := range apiKeys {
|
|
distinctUsers[apiKey.UserID] = struct{}{}
|
|
}
|
|
gauge.Set(float64(len(distinctUsers)))
|
|
}
|
|
}()
|
|
return cancelFunc, nil
|
|
}
|
|
|
|
// Workspaces tracks the total number of workspaces with labels on status.
|
|
func Workspaces(ctx context.Context, registerer prometheus.Registerer, db database.Store, duration time.Duration) (context.CancelFunc, error) {
|
|
if duration == 0 {
|
|
duration = 5 * time.Minute
|
|
}
|
|
|
|
gauge := prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
|
Namespace: "coderd",
|
|
Subsystem: "api",
|
|
Name: "workspace_latest_build_total",
|
|
Help: "The latest workspace builds with a status.",
|
|
}, []string{"status"})
|
|
err := registerer.Register(gauge)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// This exists so the prometheus metric exports immediately when set.
|
|
// It helps with tests so they don't have to wait for a tick.
|
|
gauge.WithLabelValues("pending").Set(0)
|
|
|
|
ctx, cancelFunc := context.WithCancel(ctx)
|
|
ticker := time.NewTicker(duration)
|
|
go func() {
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
}
|
|
builds, err := db.GetLatestWorkspaceBuilds(ctx)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
jobIDs := make([]uuid.UUID, 0, len(builds))
|
|
for _, build := range builds {
|
|
jobIDs = append(jobIDs, build.JobID)
|
|
}
|
|
jobs, err := db.GetProvisionerJobsByIDs(ctx, jobIDs)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
gauge.Reset()
|
|
for _, job := range jobs {
|
|
status := coderd.ConvertProvisionerJobStatus(job)
|
|
gauge.WithLabelValues(string(status)).Add(1)
|
|
}
|
|
}
|
|
}()
|
|
return cancelFunc, nil
|
|
}
|