set.go (12034B)
1 // Copyright The OpenTelemetry Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package attribute // import "go.opentelemetry.io/otel/attribute" 16 17 import ( 18 "encoding/json" 19 "reflect" 20 "sort" 21 "sync" 22 ) 23 24 type ( 25 // Set is the representation for a distinct attribute set. It manages an 26 // immutable set of attributes, with an internal cache for storing 27 // attribute encodings. 28 // 29 // This type supports the Equivalent method of comparison using values of 30 // type Distinct. 31 Set struct { 32 equivalent Distinct 33 } 34 35 // Distinct wraps a variable-size array of KeyValue, constructed with keys 36 // in sorted order. This can be used as a map key or for equality checking 37 // between Sets. 38 Distinct struct { 39 iface interface{} 40 } 41 42 // Filter supports removing certain attributes from attribute sets. When 43 // the filter returns true, the attribute will be kept in the filtered 44 // attribute set. When the filter returns false, the attribute is excluded 45 // from the filtered attribute set, and the attribute instead appears in 46 // the removed list of excluded attributes. 47 Filter func(KeyValue) bool 48 49 // Sortable implements sort.Interface, used for sorting KeyValue. This is 50 // an exported type to support a memory optimization. A pointer to one of 51 // these is needed for the call to sort.Stable(), which the caller may 52 // provide in order to avoid an allocation. See NewSetWithSortable(). 53 Sortable []KeyValue 54 ) 55 56 var ( 57 // keyValueType is used in computeDistinctReflect. 58 keyValueType = reflect.TypeOf(KeyValue{}) 59 60 // emptySet is returned for empty attribute sets. 61 emptySet = &Set{ 62 equivalent: Distinct{ 63 iface: [0]KeyValue{}, 64 }, 65 } 66 67 // sortables is a pool of Sortables used to create Sets with a user does 68 // not provide one. 69 sortables = sync.Pool{ 70 New: func() interface{} { return new(Sortable) }, 71 } 72 ) 73 74 // EmptySet returns a reference to a Set with no elements. 75 // 76 // This is a convenience provided for optimized calling utility. 77 func EmptySet() *Set { 78 return emptySet 79 } 80 81 // reflectValue abbreviates reflect.ValueOf(d). 82 func (d Distinct) reflectValue() reflect.Value { 83 return reflect.ValueOf(d.iface) 84 } 85 86 // Valid returns true if this value refers to a valid Set. 87 func (d Distinct) Valid() bool { 88 return d.iface != nil 89 } 90 91 // Len returns the number of attributes in this set. 92 func (l *Set) Len() int { 93 if l == nil || !l.equivalent.Valid() { 94 return 0 95 } 96 return l.equivalent.reflectValue().Len() 97 } 98 99 // Get returns the KeyValue at ordered position idx in this set. 100 func (l *Set) Get(idx int) (KeyValue, bool) { 101 if l == nil || !l.equivalent.Valid() { 102 return KeyValue{}, false 103 } 104 value := l.equivalent.reflectValue() 105 106 if idx >= 0 && idx < value.Len() { 107 // Note: The Go compiler successfully avoids an allocation for 108 // the interface{} conversion here: 109 return value.Index(idx).Interface().(KeyValue), true 110 } 111 112 return KeyValue{}, false 113 } 114 115 // Value returns the value of a specified key in this set. 116 func (l *Set) Value(k Key) (Value, bool) { 117 if l == nil || !l.equivalent.Valid() { 118 return Value{}, false 119 } 120 rValue := l.equivalent.reflectValue() 121 vlen := rValue.Len() 122 123 idx := sort.Search(vlen, func(idx int) bool { 124 return rValue.Index(idx).Interface().(KeyValue).Key >= k 125 }) 126 if idx >= vlen { 127 return Value{}, false 128 } 129 keyValue := rValue.Index(idx).Interface().(KeyValue) 130 if k == keyValue.Key { 131 return keyValue.Value, true 132 } 133 return Value{}, false 134 } 135 136 // HasValue tests whether a key is defined in this set. 137 func (l *Set) HasValue(k Key) bool { 138 if l == nil { 139 return false 140 } 141 _, ok := l.Value(k) 142 return ok 143 } 144 145 // Iter returns an iterator for visiting the attributes in this set. 146 func (l *Set) Iter() Iterator { 147 return Iterator{ 148 storage: l, 149 idx: -1, 150 } 151 } 152 153 // ToSlice returns the set of attributes belonging to this set, sorted, where 154 // keys appear no more than once. 155 func (l *Set) ToSlice() []KeyValue { 156 iter := l.Iter() 157 return iter.ToSlice() 158 } 159 160 // Equivalent returns a value that may be used as a map key. The Distinct type 161 // guarantees that the result will equal the equivalent. Distinct value of any 162 // attribute set with the same elements as this, where sets are made unique by 163 // choosing the last value in the input for any given key. 164 func (l *Set) Equivalent() Distinct { 165 if l == nil || !l.equivalent.Valid() { 166 return emptySet.equivalent 167 } 168 return l.equivalent 169 } 170 171 // Equals returns true if the argument set is equivalent to this set. 172 func (l *Set) Equals(o *Set) bool { 173 return l.Equivalent() == o.Equivalent() 174 } 175 176 // Encoded returns the encoded form of this set, according to encoder. 177 func (l *Set) Encoded(encoder Encoder) string { 178 if l == nil || encoder == nil { 179 return "" 180 } 181 182 return encoder.Encode(l.Iter()) 183 } 184 185 func empty() Set { 186 return Set{ 187 equivalent: emptySet.equivalent, 188 } 189 } 190 191 // NewSet returns a new Set. See the documentation for 192 // NewSetWithSortableFiltered for more details. 193 // 194 // Except for empty sets, this method adds an additional allocation compared 195 // with calls that include a Sortable. 196 func NewSet(kvs ...KeyValue) Set { 197 // Check for empty set. 198 if len(kvs) == 0 { 199 return empty() 200 } 201 srt := sortables.Get().(*Sortable) 202 s, _ := NewSetWithSortableFiltered(kvs, srt, nil) 203 sortables.Put(srt) 204 return s 205 } 206 207 // NewSetWithSortable returns a new Set. See the documentation for 208 // NewSetWithSortableFiltered for more details. 209 // 210 // This call includes a Sortable option as a memory optimization. 211 func NewSetWithSortable(kvs []KeyValue, tmp *Sortable) Set { 212 // Check for empty set. 213 if len(kvs) == 0 { 214 return empty() 215 } 216 s, _ := NewSetWithSortableFiltered(kvs, tmp, nil) 217 return s 218 } 219 220 // NewSetWithFiltered returns a new Set. See the documentation for 221 // NewSetWithSortableFiltered for more details. 222 // 223 // This call includes a Filter to include/exclude attribute keys from the 224 // return value. Excluded keys are returned as a slice of attribute values. 225 func NewSetWithFiltered(kvs []KeyValue, filter Filter) (Set, []KeyValue) { 226 // Check for empty set. 227 if len(kvs) == 0 { 228 return empty(), nil 229 } 230 srt := sortables.Get().(*Sortable) 231 s, filtered := NewSetWithSortableFiltered(kvs, srt, filter) 232 sortables.Put(srt) 233 return s, filtered 234 } 235 236 // NewSetWithSortableFiltered returns a new Set. 237 // 238 // Duplicate keys are eliminated by taking the last value. This 239 // re-orders the input slice so that unique last-values are contiguous 240 // at the end of the slice. 241 // 242 // This ensures the following: 243 // 244 // - Last-value-wins semantics 245 // - Caller sees the reordering, but doesn't lose values 246 // - Repeated call preserve last-value wins. 247 // 248 // Note that methods are defined on Set, although this returns Set. Callers 249 // can avoid memory allocations by: 250 // 251 // - allocating a Sortable for use as a temporary in this method 252 // - allocating a Set for storing the return value of this constructor. 253 // 254 // The result maintains a cache of encoded attributes, by attribute.EncoderID. 255 // This value should not be copied after its first use. 256 // 257 // The second []KeyValue return value is a list of attributes that were 258 // excluded by the Filter (if non-nil). 259 func NewSetWithSortableFiltered(kvs []KeyValue, tmp *Sortable, filter Filter) (Set, []KeyValue) { 260 // Check for empty set. 261 if len(kvs) == 0 { 262 return empty(), nil 263 } 264 265 *tmp = kvs 266 267 // Stable sort so the following de-duplication can implement 268 // last-value-wins semantics. 269 sort.Stable(tmp) 270 271 *tmp = nil 272 273 position := len(kvs) - 1 274 offset := position - 1 275 276 // The requirements stated above require that the stable 277 // result be placed in the end of the input slice, while 278 // overwritten values are swapped to the beginning. 279 // 280 // De-duplicate with last-value-wins semantics. Preserve 281 // duplicate values at the beginning of the input slice. 282 for ; offset >= 0; offset-- { 283 if kvs[offset].Key == kvs[position].Key { 284 continue 285 } 286 position-- 287 kvs[offset], kvs[position] = kvs[position], kvs[offset] 288 } 289 if filter != nil { 290 return filterSet(kvs[position:], filter) 291 } 292 return Set{ 293 equivalent: computeDistinct(kvs[position:]), 294 }, nil 295 } 296 297 // filterSet reorders kvs so that included keys are contiguous at the end of 298 // the slice, while excluded keys precede the included keys. 299 func filterSet(kvs []KeyValue, filter Filter) (Set, []KeyValue) { 300 var excluded []KeyValue 301 302 // Move attributes that do not match the filter so they're adjacent before 303 // calling computeDistinct(). 304 distinctPosition := len(kvs) 305 306 // Swap indistinct keys forward and distinct keys toward the 307 // end of the slice. 308 offset := len(kvs) - 1 309 for ; offset >= 0; offset-- { 310 if filter(kvs[offset]) { 311 distinctPosition-- 312 kvs[offset], kvs[distinctPosition] = kvs[distinctPosition], kvs[offset] 313 continue 314 } 315 } 316 excluded = kvs[:distinctPosition] 317 318 return Set{ 319 equivalent: computeDistinct(kvs[distinctPosition:]), 320 }, excluded 321 } 322 323 // Filter returns a filtered copy of this Set. See the documentation for 324 // NewSetWithSortableFiltered for more details. 325 func (l *Set) Filter(re Filter) (Set, []KeyValue) { 326 if re == nil { 327 return Set{ 328 equivalent: l.equivalent, 329 }, nil 330 } 331 332 // Note: This could be refactored to avoid the temporary slice 333 // allocation, if it proves to be expensive. 334 return filterSet(l.ToSlice(), re) 335 } 336 337 // computeDistinct returns a Distinct using either the fixed- or 338 // reflect-oriented code path, depending on the size of the input. The input 339 // slice is assumed to already be sorted and de-duplicated. 340 func computeDistinct(kvs []KeyValue) Distinct { 341 iface := computeDistinctFixed(kvs) 342 if iface == nil { 343 iface = computeDistinctReflect(kvs) 344 } 345 return Distinct{ 346 iface: iface, 347 } 348 } 349 350 // computeDistinctFixed computes a Distinct for small slices. It returns nil 351 // if the input is too large for this code path. 352 func computeDistinctFixed(kvs []KeyValue) interface{} { 353 switch len(kvs) { 354 case 1: 355 ptr := new([1]KeyValue) 356 copy((*ptr)[:], kvs) 357 return *ptr 358 case 2: 359 ptr := new([2]KeyValue) 360 copy((*ptr)[:], kvs) 361 return *ptr 362 case 3: 363 ptr := new([3]KeyValue) 364 copy((*ptr)[:], kvs) 365 return *ptr 366 case 4: 367 ptr := new([4]KeyValue) 368 copy((*ptr)[:], kvs) 369 return *ptr 370 case 5: 371 ptr := new([5]KeyValue) 372 copy((*ptr)[:], kvs) 373 return *ptr 374 case 6: 375 ptr := new([6]KeyValue) 376 copy((*ptr)[:], kvs) 377 return *ptr 378 case 7: 379 ptr := new([7]KeyValue) 380 copy((*ptr)[:], kvs) 381 return *ptr 382 case 8: 383 ptr := new([8]KeyValue) 384 copy((*ptr)[:], kvs) 385 return *ptr 386 case 9: 387 ptr := new([9]KeyValue) 388 copy((*ptr)[:], kvs) 389 return *ptr 390 case 10: 391 ptr := new([10]KeyValue) 392 copy((*ptr)[:], kvs) 393 return *ptr 394 default: 395 return nil 396 } 397 } 398 399 // computeDistinctReflect computes a Distinct using reflection, works for any 400 // size input. 401 func computeDistinctReflect(kvs []KeyValue) interface{} { 402 at := reflect.New(reflect.ArrayOf(len(kvs), keyValueType)).Elem() 403 for i, keyValue := range kvs { 404 *(at.Index(i).Addr().Interface().(*KeyValue)) = keyValue 405 } 406 return at.Interface() 407 } 408 409 // MarshalJSON returns the JSON encoding of the Set. 410 func (l *Set) MarshalJSON() ([]byte, error) { 411 return json.Marshal(l.equivalent.iface) 412 } 413 414 // MarshalLog is the marshaling function used by the logging system to represent this exporter. 415 func (l Set) MarshalLog() interface{} { 416 kvs := make(map[string]string) 417 for _, kv := range l.ToSlice() { 418 kvs[string(kv.Key)] = kv.Value.Emit() 419 } 420 return kvs 421 } 422 423 // Len implements sort.Interface. 424 func (l *Sortable) Len() int { 425 return len(*l) 426 } 427 428 // Swap implements sort.Interface. 429 func (l *Sortable) Swap(i, j int) { 430 (*l)[i], (*l)[j] = (*l)[j], (*l)[i] 431 } 432 433 // Less implements sort.Interface. 434 func (l *Sortable) Less(i, j int) bool { 435 return (*l)[i].Key < (*l)[j].Key 436 }