diff --git a/pkg/prometheus/prometheus.go b/pkg/prometheus/prometheus.go index f645065b7..3d503219f 100644 --- a/pkg/prometheus/prometheus.go +++ b/pkg/prometheus/prometheus.go @@ -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 diff --git a/runsc/cmd/metric_server.go b/runsc/cmd/metric_server.go index 08673a69c..16337820d 100644 --- a/runsc/cmd/metric_server.go +++ b/runsc/cmd/metric_server.go @@ -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