MCPcopy
hub / github.com/grafana/tempo / Limit

Method Limit

modules/generator/registry/per_label_limiter.go:81–133  ·  view source on GitHub ↗

Limit applies the per-label cardinality limit to the given labels. Labels whose estimated cardinality exceeds the configured max have their value replaced with __cardinality_overflow__.

(lbls labels.Labels)

Source from the content-addressed store, hash-verified

79// Labels whose estimated cardinality exceeds the configured max have their
80// value replaced with __cardinality_overflow__.
81func (s *PerLabelLimiter) Limit(lbls labels.Labels) labels.Labels {
82 // do maintenance check as the first thing to ensure maxCardinality
83 // is refreshed from runtime overrides. without this,
84 // a limiter that starts disabled would never be enabled without restart.
85 s.doPeriodicMaintenance()
86
87 // maxCardinality is zero, so limiter is disabled, return labels as is
88 if s.maxCardinality.Load() == 0 {
89 return lbls
90 }
91
92 s.mtx.Lock()
93 defer s.mtx.Unlock()
94
95 // Defer builder creation until we actually need to modify a label.
96 // In the common case (no overflow), we avoid the allocations entirely.
97 var builder *labels.Builder
98 lbls.Range(func(l labels.Label) {
99 // skip over the metadata labels
100 if schema.IsMetadataLabel(l.Name) {
101 return
102 }
103
104 state := s.getOrCreateState(l.Name)
105
106 // we always insert the ORIGINAL value to hash even while overflowing,
107 // which prevents the estimate from artificially dropping.
108 // It will make sure that recovery (label going back under limit) only happens when the
109 // actual incoming data has lower cardinality AND the old sketches have been rotated out.
110 //
111 // If we inserted the overflowValue, then the estimate would drop and cause oscillation:
112 // over limit -> Add overflowValue -> estimate drops -> under limit -> real values -> over limit ->...
113 // Insert acquires its own internal mu lock on the sketch.
114 state.sketch.Insert(xxhash.Sum64String(l.Value))
115
116 // we are over the limit, replace label value and capture the metric
117 if state.overLimit {
118 // Lazy init: only create once, so previous Set calls are preserved
119 // when multiple labels overflow in the same series
120 if builder == nil {
121 builder = labels.NewBuilder(lbls)
122 }
123 builder.Set(l.Name, overflowValue)
124 metricLabelValuesLimited.WithLabelValues(s.tenant, l.Name).Inc()
125 }
126 })
127
128 // No labels were limited, return the original labels as is.
129 if builder == nil {
130 return lbls
131 }
132 return builder.Labels()
133}
134
135func (s *PerLabelLimiter) getOrCreateState(labelName string) *labelCardinalityState {
136 state, ok := s.labelsState[labelName]

Calls 5

doPeriodicMaintenanceMethod · 0.95
getOrCreateStateMethod · 0.95
InsertMethod · 0.80
SetMethod · 0.65
IncMethod · 0.65