Skip to content

feat: use map instead of slice in metrics aggregator #11815

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 29, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use struct key
  • Loading branch information
mtojek committed Jan 25, 2024
commit 12fcdab17f3d441c5b7618d259bb1a8abef79a70
58 changes: 41 additions & 17 deletions coderd/prometheusmetrics/aggregator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package prometheusmetrics

import (
"context"
"fmt"
"strings"
"time"

Expand Down Expand Up @@ -32,7 +31,7 @@ const (
)

type MetricsAggregator struct {
store map[string]annotatedMetric
store map[metricKey]annotatedMetric

log slog.Logger
metricsCleanupInterval time.Duration
Expand Down Expand Up @@ -67,29 +66,54 @@ type annotatedMetric struct {
expiryDate time.Time
}

func hashKey(req *updateRequest, m *agentproto.Stats_Metric) string {
var sbLabels strings.Builder
for i, label := range m.GetLabels() {
_, _ = sbLabels.WriteString(label.Name)
_ = sbLabels.WriteByte('=')
_, _ = sbLabels.WriteString(label.Value)
type metricKey struct {
username string
workspaceName string
agentName string
templateName string

if i-1 != len(m.GetLabels()) {
_ = sbLabels.WriteByte(',')
}
metricName string
labelsStr string
}

func (m1 metricKey) Equal(m2 metricKey) bool {
return m1.metricName == m2.metricName &&
m1.labelsStr == m2.labelsStr &&
m1.username == m2.username &&
m1.workspaceName == m2.workspaceName &&
m1.agentName == m2.agentName &&
m1.templateName == m2.templateName
}

func hashKey(req *updateRequest, m *agentproto.Stats_Metric) metricKey {
var sb strings.Builder
for _, label := range m.GetLabels() {
_, _ = sb.WriteString(label.Name)
_ = sb.WriteByte('=')
_, _ = sb.WriteString(label.Value)
_ = sb.WriteByte(',')
}
labels := strings.TrimRight(sb.String(), ",")

return metricKey{
username: req.username,
workspaceName: req.workspaceName,
agentName: req.agentName,
templateName: req.templateName,
metricName: m.Name,
labelsStr: labels,
}
return fmt.Sprintf("%s|%s|%s|%s|%s|%s", req.username, req.workspaceName, req.agentName, req.templateName, m.GetName(), sbLabels.String())
}

var _ prometheus.Collector = new(MetricsAggregator)

func (am *annotatedMetric) is(req updateRequest, m *agentproto.Stats_Metric) bool {
return am.username == req.username &&
return am.Name == m.Name &&
agentproto.LabelsEqual(am.Labels, m.Labels) &&
am.username == req.username &&
am.workspaceName == req.workspaceName &&
am.agentName == req.agentName &&
am.templateName == req.templateName &&
am.Name == m.Name &&
agentproto.LabelsEqual(am.Labels, m.Labels)
am.templateName == req.templateName
}

func (am *annotatedMetric) asPrometheus() (prometheus.Metric, error) {
Expand Down Expand Up @@ -157,7 +181,7 @@ func NewMetricsAggregator(logger slog.Logger, registerer prometheus.Registerer,
log: logger.Named(loggerName),
metricsCleanupInterval: metricsCleanupInterval,

store: map[string]annotatedMetric{},
store: map[metricKey]annotatedMetric{},

collectCh: make(chan (chan []prometheus.Metric), sizeCollectCh),
updateCh: make(chan updateRequest, sizeUpdateCh),
Expand Down