Add a secondary label map to prometheus.Data.

This is useful for metrics where some labels are specific to the `Data` struct
in question, while others are shared. It is wasteful to create unique maps
for each `*Data` when they contain mostly the same labels.

There used to only be one such metric that requires data labels, but an
upcoming change will change that, making this change worthwhile to avoid
wasting memory.

PiperOrigin-RevId: 521596697
This commit is contained in:
Etienne Perot
2023-04-03 16:44:47 -07:00
committed by gVisor bot
parent 3c2f1972c2
commit 0776a6d557
2 changed files with 23 additions and 18 deletions
+18 -2
View File
@@ -314,6 +314,15 @@ type Data struct {
// This may be merged with other labels during export.
Labels map[string]string `json:"labels,omitempty"`
// ExternalLabels are more labels merged together with `Labels`.
// They can be set using SetExternalLabels.
// They are useful in the case where a single Data needs labels from two sources:
// labels specific to this data point (which should be in `Labels`), and labels
// that are shared between multiple data points (stored in `ExternalLabels`).
// This avoids allocating unique `Labels` maps for each Data struct, when
// most of the actual labels would be shared between them.
ExternalLabels map[string]string `json:"external_labels,omitempty"`
// At most one of the fields below may be set.
// Which one depends on the type of the metric.
@@ -344,6 +353,13 @@ func LabeledFloatData(metric *Metric, labels map[string]string, val float64) *Da
return &Data{Metric: metric, Labels: labels, Number: NewFloat(val)}
}
// SetExternalLabels sets d.ExternalLabels. See its docstring for more information.
// Returns `d` for chainability.
func (d *Data) SetExternalLabels(externalLabels map[string]string) *Data {
d.ExternalLabels = externalLabels
return d
}
// ExportOptions contains options that control how metric data is exported in Prometheus format.
type ExportOptions struct {
// CommentHeader is prepended as a comment before any metric data is exported.
@@ -650,9 +666,9 @@ func (d *Data) writeLabelsTo(w io.Writer, extraLabels map[string]string, leLabel
}
var orderedLabels <-chan LabelOrError
if leLabel != nil {
orderedLabels = OrderedLabels(d.Labels, extraLabels, map[string]string{"le": leLabel.String()})
orderedLabels = OrderedLabels(d.Labels, d.ExternalLabels, extraLabels, map[string]string{"le": leLabel.String()})
} else {
orderedLabels = OrderedLabels(d.Labels, extraLabels)
orderedLabels = OrderedLabels(d.Labels, d.ExternalLabels, extraLabels)
}
firstLabel := true
var foundError error
+5 -16
View File
@@ -89,11 +89,6 @@ type servedSandbox struct {
// Once set, it is immutable.
createdAt time.Time
// labelsWithMetadata is the union of `extraLabels` and `sandbox.MetricMetadata`.
// This is exported as the set of labels for the `sandbox_metadata` metric.
// Once set, it is immutable.
labelsWithMetadata map[string]string
// verifier allows verifying the data integrity of the metrics we get from this sandbox.
// It is not always initialized when the sandbox is discovered, but rather upon first metrics
// access to the sandbox. Metric registration data is loaded from the root container's
@@ -197,13 +192,6 @@ func (s *servedSandbox) load() (*sandbox.Sandbox, *prometheus.Verifier, error) {
s.verifier = verifier
s.cleanupVerifier = cleanup
}
s.labelsWithMetadata = make(map[string]string, len(s.extraLabels)+len(s.sandbox.MetricMetadata))
for k, v := range s.extraLabels {
s.labelsWithMetadata[k] = v
}
for k, v := range s.sandbox.MetricMetadata {
s.labelsWithMetadata[k] = v
}
return s.sandbox, s.verifier, nil
}
@@ -691,16 +679,17 @@ func (m *MetricServer) serveMetrics(w http.ResponseWriter, req *http.Request) ht
func() {
metricsMu.Lock()
defer metricsMu.Unlock()
selfMetrics.Add(prometheus.LabeledIntData(&SandboxPresenceMetric, served.extraLabels, 1))
selfMetrics.Add(prometheus.LabeledIntData(&SandboxPresenceMetric, nil, 1).SetExternalLabels(served.extraLabels))
sandboxRunning := int64(0)
if isRunning {
sandboxRunning = 1
meta.numRunningSandboxes++
}
selfMetrics.Add(prometheus.LabeledIntData(&SandboxRunningMetric, served.extraLabels, sandboxRunning))
selfMetrics.Add(prometheus.LabeledIntData(&SandboxRunningMetric, nil, sandboxRunning).SetExternalLabels(served.extraLabels))
if loadErr == nil {
selfMetrics.Add(prometheus.LabeledIntData(&SandboxMetadataMetric, served.labelsWithMetadata, 1))
selfMetrics.Add(prometheus.LabeledFloatData(&SandboxCreationMetric, served.extraLabels, float64(served.createdAt.Unix())+(float64(served.createdAt.Nanosecond())/1e9)))
selfMetrics.Add(prometheus.LabeledIntData(&SandboxMetadataMetric, sand.MetricMetadata, 1).SetExternalLabels(served.extraLabels))
createdAt := float64(served.createdAt.Unix()) + (float64(served.createdAt.Nanosecond()) / 1e9)
selfMetrics.Add(prometheus.LabeledFloatData(&SandboxCreationMetric, nil, createdAt).SetExternalLabels(served.extraLabels))
}
if sandboxErr != nil {
// If the sandbox isn't running, it is normal that metrics are not exported for it, so