| Abhay Kumar | 40252eb | 2025-10-13 13:25:53 +0000 | [diff] [blame^] | 1 | // Copyright The OpenTelemetry Authors |
| 2 | // SPDX-License-Identifier: Apache-2.0 |
| 3 | |
| 4 | package attribute // import "go.opentelemetry.io/otel/attribute" |
| 5 | |
| 6 | import ( |
| 7 | "cmp" |
| 8 | "encoding/json" |
| 9 | "reflect" |
| 10 | "slices" |
| 11 | "sort" |
| 12 | ) |
| 13 | |
| 14 | type ( |
| 15 | // Set is the representation for a distinct attribute set. It manages an |
| 16 | // immutable set of attributes, with an internal cache for storing |
| 17 | // attribute encodings. |
| 18 | // |
| 19 | // This type will remain comparable for backwards compatibility. The |
| 20 | // equivalence of Sets across versions is not guaranteed to be stable. |
| 21 | // Prior versions may find two Sets to be equal or not when compared |
| 22 | // directly (i.e. ==), but subsequent versions may not. Users should use |
| 23 | // the Equals method to ensure stable equivalence checking. |
| 24 | // |
| 25 | // Users should also use the Distinct returned from Equivalent as a map key |
| 26 | // instead of a Set directly. In addition to that type providing guarantees |
| 27 | // on stable equivalence, it may also provide performance improvements. |
| 28 | Set struct { |
| 29 | equivalent Distinct |
| 30 | } |
| 31 | |
| 32 | // Distinct is a unique identifier of a Set. |
| 33 | // |
| 34 | // Distinct is designed to be ensures equivalence stability: comparisons |
| 35 | // will return the save value across versions. For this reason, Distinct |
| 36 | // should always be used as a map key instead of a Set. |
| 37 | Distinct struct { |
| 38 | iface interface{} |
| 39 | } |
| 40 | |
| 41 | // Sortable implements sort.Interface, used for sorting KeyValue. |
| 42 | // |
| 43 | // Deprecated: This type is no longer used. It was added as a performance |
| 44 | // optimization for Go < 1.21 that is no longer needed (Go < 1.21 is no |
| 45 | // longer supported by the module). |
| 46 | Sortable []KeyValue |
| 47 | ) |
| 48 | |
| 49 | var ( |
| 50 | // keyValueType is used in computeDistinctReflect. |
| 51 | keyValueType = reflect.TypeOf(KeyValue{}) |
| 52 | |
| 53 | // emptySet is returned for empty attribute sets. |
| 54 | emptySet = &Set{ |
| 55 | equivalent: Distinct{ |
| 56 | iface: [0]KeyValue{}, |
| 57 | }, |
| 58 | } |
| 59 | ) |
| 60 | |
| 61 | // EmptySet returns a reference to a Set with no elements. |
| 62 | // |
| 63 | // This is a convenience provided for optimized calling utility. |
| 64 | func EmptySet() *Set { |
| 65 | return emptySet |
| 66 | } |
| 67 | |
| 68 | // reflectValue abbreviates reflect.ValueOf(d). |
| 69 | func (d Distinct) reflectValue() reflect.Value { |
| 70 | return reflect.ValueOf(d.iface) |
| 71 | } |
| 72 | |
| 73 | // Valid returns true if this value refers to a valid Set. |
| 74 | func (d Distinct) Valid() bool { |
| 75 | return d.iface != nil |
| 76 | } |
| 77 | |
| 78 | // Len returns the number of attributes in this set. |
| 79 | func (l *Set) Len() int { |
| 80 | if l == nil || !l.equivalent.Valid() { |
| 81 | return 0 |
| 82 | } |
| 83 | return l.equivalent.reflectValue().Len() |
| 84 | } |
| 85 | |
| 86 | // Get returns the KeyValue at ordered position idx in this set. |
| 87 | func (l *Set) Get(idx int) (KeyValue, bool) { |
| 88 | if l == nil || !l.equivalent.Valid() { |
| 89 | return KeyValue{}, false |
| 90 | } |
| 91 | value := l.equivalent.reflectValue() |
| 92 | |
| 93 | if idx >= 0 && idx < value.Len() { |
| 94 | // Note: The Go compiler successfully avoids an allocation for |
| 95 | // the interface{} conversion here: |
| 96 | return value.Index(idx).Interface().(KeyValue), true |
| 97 | } |
| 98 | |
| 99 | return KeyValue{}, false |
| 100 | } |
| 101 | |
| 102 | // Value returns the value of a specified key in this set. |
| 103 | func (l *Set) Value(k Key) (Value, bool) { |
| 104 | if l == nil || !l.equivalent.Valid() { |
| 105 | return Value{}, false |
| 106 | } |
| 107 | rValue := l.equivalent.reflectValue() |
| 108 | vlen := rValue.Len() |
| 109 | |
| 110 | idx := sort.Search(vlen, func(idx int) bool { |
| 111 | return rValue.Index(idx).Interface().(KeyValue).Key >= k |
| 112 | }) |
| 113 | if idx >= vlen { |
| 114 | return Value{}, false |
| 115 | } |
| 116 | keyValue := rValue.Index(idx).Interface().(KeyValue) |
| 117 | if k == keyValue.Key { |
| 118 | return keyValue.Value, true |
| 119 | } |
| 120 | return Value{}, false |
| 121 | } |
| 122 | |
| 123 | // HasValue tests whether a key is defined in this set. |
| 124 | func (l *Set) HasValue(k Key) bool { |
| 125 | if l == nil { |
| 126 | return false |
| 127 | } |
| 128 | _, ok := l.Value(k) |
| 129 | return ok |
| 130 | } |
| 131 | |
| 132 | // Iter returns an iterator for visiting the attributes in this set. |
| 133 | func (l *Set) Iter() Iterator { |
| 134 | return Iterator{ |
| 135 | storage: l, |
| 136 | idx: -1, |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | // ToSlice returns the set of attributes belonging to this set, sorted, where |
| 141 | // keys appear no more than once. |
| 142 | func (l *Set) ToSlice() []KeyValue { |
| 143 | iter := l.Iter() |
| 144 | return iter.ToSlice() |
| 145 | } |
| 146 | |
| 147 | // Equivalent returns a value that may be used as a map key. The Distinct type |
| 148 | // guarantees that the result will equal the equivalent. Distinct value of any |
| 149 | // attribute set with the same elements as this, where sets are made unique by |
| 150 | // choosing the last value in the input for any given key. |
| 151 | func (l *Set) Equivalent() Distinct { |
| 152 | if l == nil || !l.equivalent.Valid() { |
| 153 | return emptySet.equivalent |
| 154 | } |
| 155 | return l.equivalent |
| 156 | } |
| 157 | |
| 158 | // Equals returns true if the argument set is equivalent to this set. |
| 159 | func (l *Set) Equals(o *Set) bool { |
| 160 | return l.Equivalent() == o.Equivalent() |
| 161 | } |
| 162 | |
| 163 | // Encoded returns the encoded form of this set, according to encoder. |
| 164 | func (l *Set) Encoded(encoder Encoder) string { |
| 165 | if l == nil || encoder == nil { |
| 166 | return "" |
| 167 | } |
| 168 | |
| 169 | return encoder.Encode(l.Iter()) |
| 170 | } |
| 171 | |
| 172 | func empty() Set { |
| 173 | return Set{ |
| 174 | equivalent: emptySet.equivalent, |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | // NewSet returns a new Set. See the documentation for |
| 179 | // NewSetWithSortableFiltered for more details. |
| 180 | // |
| 181 | // Except for empty sets, this method adds an additional allocation compared |
| 182 | // with calls that include a Sortable. |
| 183 | func NewSet(kvs ...KeyValue) Set { |
| 184 | s, _ := NewSetWithFiltered(kvs, nil) |
| 185 | return s |
| 186 | } |
| 187 | |
| 188 | // NewSetWithSortable returns a new Set. See the documentation for |
| 189 | // NewSetWithSortableFiltered for more details. |
| 190 | // |
| 191 | // This call includes a Sortable option as a memory optimization. |
| 192 | // |
| 193 | // Deprecated: Use [NewSet] instead. |
| 194 | func NewSetWithSortable(kvs []KeyValue, _ *Sortable) Set { |
| 195 | s, _ := NewSetWithFiltered(kvs, nil) |
| 196 | return s |
| 197 | } |
| 198 | |
| 199 | // NewSetWithFiltered returns a new Set. See the documentation for |
| 200 | // NewSetWithSortableFiltered for more details. |
| 201 | // |
| 202 | // This call includes a Filter to include/exclude attribute keys from the |
| 203 | // return value. Excluded keys are returned as a slice of attribute values. |
| 204 | func NewSetWithFiltered(kvs []KeyValue, filter Filter) (Set, []KeyValue) { |
| 205 | // Check for empty set. |
| 206 | if len(kvs) == 0 { |
| 207 | return empty(), nil |
| 208 | } |
| 209 | |
| 210 | // Stable sort so the following de-duplication can implement |
| 211 | // last-value-wins semantics. |
| 212 | slices.SortStableFunc(kvs, func(a, b KeyValue) int { |
| 213 | return cmp.Compare(a.Key, b.Key) |
| 214 | }) |
| 215 | |
| 216 | position := len(kvs) - 1 |
| 217 | offset := position - 1 |
| 218 | |
| 219 | // The requirements stated above require that the stable |
| 220 | // result be placed in the end of the input slice, while |
| 221 | // overwritten values are swapped to the beginning. |
| 222 | // |
| 223 | // De-duplicate with last-value-wins semantics. Preserve |
| 224 | // duplicate values at the beginning of the input slice. |
| 225 | for ; offset >= 0; offset-- { |
| 226 | if kvs[offset].Key == kvs[position].Key { |
| 227 | continue |
| 228 | } |
| 229 | position-- |
| 230 | kvs[offset], kvs[position] = kvs[position], kvs[offset] |
| 231 | } |
| 232 | kvs = kvs[position:] |
| 233 | |
| 234 | if filter != nil { |
| 235 | if div := filteredToFront(kvs, filter); div != 0 { |
| 236 | return Set{equivalent: computeDistinct(kvs[div:])}, kvs[:div] |
| 237 | } |
| 238 | } |
| 239 | return Set{equivalent: computeDistinct(kvs)}, nil |
| 240 | } |
| 241 | |
| 242 | // NewSetWithSortableFiltered returns a new Set. |
| 243 | // |
| 244 | // Duplicate keys are eliminated by taking the last value. This |
| 245 | // re-orders the input slice so that unique last-values are contiguous |
| 246 | // at the end of the slice. |
| 247 | // |
| 248 | // This ensures the following: |
| 249 | // |
| 250 | // - Last-value-wins semantics |
| 251 | // - Caller sees the reordering, but doesn't lose values |
| 252 | // - Repeated call preserve last-value wins. |
| 253 | // |
| 254 | // Note that methods are defined on Set, although this returns Set. Callers |
| 255 | // can avoid memory allocations by: |
| 256 | // |
| 257 | // - allocating a Sortable for use as a temporary in this method |
| 258 | // - allocating a Set for storing the return value of this constructor. |
| 259 | // |
| 260 | // The result maintains a cache of encoded attributes, by attribute.EncoderID. |
| 261 | // This value should not be copied after its first use. |
| 262 | // |
| 263 | // The second []KeyValue return value is a list of attributes that were |
| 264 | // excluded by the Filter (if non-nil). |
| 265 | // |
| 266 | // Deprecated: Use [NewSetWithFiltered] instead. |
| 267 | func NewSetWithSortableFiltered(kvs []KeyValue, _ *Sortable, filter Filter) (Set, []KeyValue) { |
| 268 | return NewSetWithFiltered(kvs, filter) |
| 269 | } |
| 270 | |
| 271 | // filteredToFront filters slice in-place using keep function. All KeyValues that need to |
| 272 | // be removed are moved to the front. All KeyValues that need to be kept are |
| 273 | // moved (in-order) to the back. The index for the first KeyValue to be kept is |
| 274 | // returned. |
| 275 | func filteredToFront(slice []KeyValue, keep Filter) int { |
| 276 | n := len(slice) |
| 277 | j := n |
| 278 | for i := n - 1; i >= 0; i-- { |
| 279 | if keep(slice[i]) { |
| 280 | j-- |
| 281 | slice[i], slice[j] = slice[j], slice[i] |
| 282 | } |
| 283 | } |
| 284 | return j |
| 285 | } |
| 286 | |
| 287 | // Filter returns a filtered copy of this Set. See the documentation for |
| 288 | // NewSetWithSortableFiltered for more details. |
| 289 | func (l *Set) Filter(re Filter) (Set, []KeyValue) { |
| 290 | if re == nil { |
| 291 | return *l, nil |
| 292 | } |
| 293 | |
| 294 | // Iterate in reverse to the first attribute that will be filtered out. |
| 295 | n := l.Len() |
| 296 | first := n - 1 |
| 297 | for ; first >= 0; first-- { |
| 298 | kv, _ := l.Get(first) |
| 299 | if !re(kv) { |
| 300 | break |
| 301 | } |
| 302 | } |
| 303 | |
| 304 | // No attributes will be dropped, return the immutable Set l and nil. |
| 305 | if first < 0 { |
| 306 | return *l, nil |
| 307 | } |
| 308 | |
| 309 | // Copy now that we know we need to return a modified set. |
| 310 | // |
| 311 | // Do not do this in-place on the underlying storage of *Set l. Sets are |
| 312 | // immutable and filtering should not change this. |
| 313 | slice := l.ToSlice() |
| 314 | |
| 315 | // Don't re-iterate the slice if only slice[0] is filtered. |
| 316 | if first == 0 { |
| 317 | // It is safe to assume len(slice) >= 1 given we found at least one |
| 318 | // attribute above that needs to be filtered out. |
| 319 | return Set{equivalent: computeDistinct(slice[1:])}, slice[:1] |
| 320 | } |
| 321 | |
| 322 | // Move the filtered slice[first] to the front (preserving order). |
| 323 | kv := slice[first] |
| 324 | copy(slice[1:first+1], slice[:first]) |
| 325 | slice[0] = kv |
| 326 | |
| 327 | // Do not re-evaluate re(slice[first+1:]). |
| 328 | div := filteredToFront(slice[1:first+1], re) + 1 |
| 329 | return Set{equivalent: computeDistinct(slice[div:])}, slice[:div] |
| 330 | } |
| 331 | |
| 332 | // computeDistinct returns a Distinct using either the fixed- or |
| 333 | // reflect-oriented code path, depending on the size of the input. The input |
| 334 | // slice is assumed to already be sorted and de-duplicated. |
| 335 | func computeDistinct(kvs []KeyValue) Distinct { |
| 336 | iface := computeDistinctFixed(kvs) |
| 337 | if iface == nil { |
| 338 | iface = computeDistinctReflect(kvs) |
| 339 | } |
| 340 | return Distinct{ |
| 341 | iface: iface, |
| 342 | } |
| 343 | } |
| 344 | |
| 345 | // computeDistinctFixed computes a Distinct for small slices. It returns nil |
| 346 | // if the input is too large for this code path. |
| 347 | func computeDistinctFixed(kvs []KeyValue) interface{} { |
| 348 | switch len(kvs) { |
| 349 | case 1: |
| 350 | return [1]KeyValue(kvs) |
| 351 | case 2: |
| 352 | return [2]KeyValue(kvs) |
| 353 | case 3: |
| 354 | return [3]KeyValue(kvs) |
| 355 | case 4: |
| 356 | return [4]KeyValue(kvs) |
| 357 | case 5: |
| 358 | return [5]KeyValue(kvs) |
| 359 | case 6: |
| 360 | return [6]KeyValue(kvs) |
| 361 | case 7: |
| 362 | return [7]KeyValue(kvs) |
| 363 | case 8: |
| 364 | return [8]KeyValue(kvs) |
| 365 | case 9: |
| 366 | return [9]KeyValue(kvs) |
| 367 | case 10: |
| 368 | return [10]KeyValue(kvs) |
| 369 | default: |
| 370 | return nil |
| 371 | } |
| 372 | } |
| 373 | |
| 374 | // computeDistinctReflect computes a Distinct using reflection, works for any |
| 375 | // size input. |
| 376 | func computeDistinctReflect(kvs []KeyValue) interface{} { |
| 377 | at := reflect.New(reflect.ArrayOf(len(kvs), keyValueType)).Elem() |
| 378 | for i, keyValue := range kvs { |
| 379 | *(at.Index(i).Addr().Interface().(*KeyValue)) = keyValue |
| 380 | } |
| 381 | return at.Interface() |
| 382 | } |
| 383 | |
| 384 | // MarshalJSON returns the JSON encoding of the Set. |
| 385 | func (l *Set) MarshalJSON() ([]byte, error) { |
| 386 | return json.Marshal(l.equivalent.iface) |
| 387 | } |
| 388 | |
| 389 | // MarshalLog is the marshaling function used by the logging system to represent this Set. |
| 390 | func (l Set) MarshalLog() interface{} { |
| 391 | kvs := make(map[string]string) |
| 392 | for _, kv := range l.ToSlice() { |
| 393 | kvs[string(kv.Key)] = kv.Value.Emit() |
| 394 | } |
| 395 | return kvs |
| 396 | } |
| 397 | |
| 398 | // Len implements sort.Interface. |
| 399 | func (l *Sortable) Len() int { |
| 400 | return len(*l) |
| 401 | } |
| 402 | |
| 403 | // Swap implements sort.Interface. |
| 404 | func (l *Sortable) Swap(i, j int) { |
| 405 | (*l)[i], (*l)[j] = (*l)[j], (*l)[i] |
| 406 | } |
| 407 | |
| 408 | // Less implements sort.Interface. |
| 409 | func (l *Sortable) Less(i, j int) bool { |
| 410 | return (*l)[i].Key < (*l)[j].Key |
| 411 | } |