412 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			412 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
| // Copyright The OpenTelemetry Authors
 | |
| // SPDX-License-Identifier: Apache-2.0
 | |
| 
 | |
| package attribute // import "go.opentelemetry.io/otel/attribute"
 | |
| 
 | |
| import (
 | |
| 	"cmp"
 | |
| 	"encoding/json"
 | |
| 	"reflect"
 | |
| 	"slices"
 | |
| 	"sort"
 | |
| )
 | |
| 
 | |
| type (
 | |
| 	// Set is the representation for a distinct attribute set. It manages an
 | |
| 	// immutable set of attributes, with an internal cache for storing
 | |
| 	// attribute encodings.
 | |
| 	//
 | |
| 	// This type will remain comparable for backwards compatibility. The
 | |
| 	// equivalence of Sets across versions is not guaranteed to be stable.
 | |
| 	// Prior versions may find two Sets to be equal or not when compared
 | |
| 	// directly (i.e. ==), but subsequent versions may not. Users should use
 | |
| 	// the Equals method to ensure stable equivalence checking.
 | |
| 	//
 | |
| 	// Users should also use the Distinct returned from Equivalent as a map key
 | |
| 	// instead of a Set directly. In addition to that type providing guarantees
 | |
| 	// on stable equivalence, it may also provide performance improvements.
 | |
| 	Set struct {
 | |
| 		equivalent Distinct
 | |
| 	}
 | |
| 
 | |
| 	// Distinct is a unique identifier of a Set.
 | |
| 	//
 | |
| 	// Distinct is designed to be ensures equivalence stability: comparisons
 | |
| 	// will return the save value across versions. For this reason, Distinct
 | |
| 	// should always be used as a map key instead of a Set.
 | |
| 	Distinct struct {
 | |
| 		iface interface{}
 | |
| 	}
 | |
| 
 | |
| 	// Sortable implements sort.Interface, used for sorting KeyValue.
 | |
| 	//
 | |
| 	// Deprecated: This type is no longer used. It was added as a performance
 | |
| 	// optimization for Go < 1.21 that is no longer needed (Go < 1.21 is no
 | |
| 	// longer supported by the module).
 | |
| 	Sortable []KeyValue
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	// keyValueType is used in computeDistinctReflect.
 | |
| 	keyValueType = reflect.TypeOf(KeyValue{})
 | |
| 
 | |
| 	// emptySet is returned for empty attribute sets.
 | |
| 	emptySet = &Set{
 | |
| 		equivalent: Distinct{
 | |
| 			iface: [0]KeyValue{},
 | |
| 		},
 | |
| 	}
 | |
| )
 | |
| 
 | |
| // EmptySet returns a reference to a Set with no elements.
 | |
| //
 | |
| // This is a convenience provided for optimized calling utility.
 | |
| func EmptySet() *Set {
 | |
| 	return emptySet
 | |
| }
 | |
| 
 | |
| // reflectValue abbreviates reflect.ValueOf(d).
 | |
| func (d Distinct) reflectValue() reflect.Value {
 | |
| 	return reflect.ValueOf(d.iface)
 | |
| }
 | |
| 
 | |
| // Valid reports whether this value refers to a valid Set.
 | |
| func (d Distinct) Valid() bool {
 | |
| 	return d.iface != nil
 | |
| }
 | |
| 
 | |
| // Len returns the number of attributes in this set.
 | |
| func (l *Set) Len() int {
 | |
| 	if l == nil || !l.equivalent.Valid() {
 | |
| 		return 0
 | |
| 	}
 | |
| 	return l.equivalent.reflectValue().Len()
 | |
| }
 | |
| 
 | |
| // Get returns the KeyValue at ordered position idx in this set.
 | |
| func (l *Set) Get(idx int) (KeyValue, bool) {
 | |
| 	if l == nil || !l.equivalent.Valid() {
 | |
| 		return KeyValue{}, false
 | |
| 	}
 | |
| 	value := l.equivalent.reflectValue()
 | |
| 
 | |
| 	if idx >= 0 && idx < value.Len() {
 | |
| 		// Note: The Go compiler successfully avoids an allocation for
 | |
| 		// the interface{} conversion here:
 | |
| 		return value.Index(idx).Interface().(KeyValue), true
 | |
| 	}
 | |
| 
 | |
| 	return KeyValue{}, false
 | |
| }
 | |
| 
 | |
| // Value returns the value of a specified key in this set.
 | |
| func (l *Set) Value(k Key) (Value, bool) {
 | |
| 	if l == nil || !l.equivalent.Valid() {
 | |
| 		return Value{}, false
 | |
| 	}
 | |
| 	rValue := l.equivalent.reflectValue()
 | |
| 	vlen := rValue.Len()
 | |
| 
 | |
| 	idx := sort.Search(vlen, func(idx int) bool {
 | |
| 		return rValue.Index(idx).Interface().(KeyValue).Key >= k
 | |
| 	})
 | |
| 	if idx >= vlen {
 | |
| 		return Value{}, false
 | |
| 	}
 | |
| 	keyValue := rValue.Index(idx).Interface().(KeyValue)
 | |
| 	if k == keyValue.Key {
 | |
| 		return keyValue.Value, true
 | |
| 	}
 | |
| 	return Value{}, false
 | |
| }
 | |
| 
 | |
| // HasValue reports whether a key is defined in this set.
 | |
| func (l *Set) HasValue(k Key) bool {
 | |
| 	if l == nil {
 | |
| 		return false
 | |
| 	}
 | |
| 	_, ok := l.Value(k)
 | |
| 	return ok
 | |
| }
 | |
| 
 | |
| // Iter returns an iterator for visiting the attributes in this set.
 | |
| func (l *Set) Iter() Iterator {
 | |
| 	return Iterator{
 | |
| 		storage: l,
 | |
| 		idx:     -1,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // ToSlice returns the set of attributes belonging to this set, sorted, where
 | |
| // keys appear no more than once.
 | |
| func (l *Set) ToSlice() []KeyValue {
 | |
| 	iter := l.Iter()
 | |
| 	return iter.ToSlice()
 | |
| }
 | |
| 
 | |
| // Equivalent returns a value that may be used as a map key. The Distinct type
 | |
| // guarantees that the result will equal the equivalent. Distinct value of any
 | |
| // attribute set with the same elements as this, where sets are made unique by
 | |
| // choosing the last value in the input for any given key.
 | |
| func (l *Set) Equivalent() Distinct {
 | |
| 	if l == nil || !l.equivalent.Valid() {
 | |
| 		return emptySet.equivalent
 | |
| 	}
 | |
| 	return l.equivalent
 | |
| }
 | |
| 
 | |
| // Equals reports whether the argument set is equivalent to this set.
 | |
| func (l *Set) Equals(o *Set) bool {
 | |
| 	return l.Equivalent() == o.Equivalent()
 | |
| }
 | |
| 
 | |
| // Encoded returns the encoded form of this set, according to encoder.
 | |
| func (l *Set) Encoded(encoder Encoder) string {
 | |
| 	if l == nil || encoder == nil {
 | |
| 		return ""
 | |
| 	}
 | |
| 
 | |
| 	return encoder.Encode(l.Iter())
 | |
| }
 | |
| 
 | |
| func empty() Set {
 | |
| 	return Set{
 | |
| 		equivalent: emptySet.equivalent,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // NewSet returns a new Set. See the documentation for
 | |
| // NewSetWithSortableFiltered for more details.
 | |
| //
 | |
| // Except for empty sets, this method adds an additional allocation compared
 | |
| // with calls that include a Sortable.
 | |
| func NewSet(kvs ...KeyValue) Set {
 | |
| 	s, _ := NewSetWithFiltered(kvs, nil)
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| // NewSetWithSortable returns a new Set. See the documentation for
 | |
| // NewSetWithSortableFiltered for more details.
 | |
| //
 | |
| // This call includes a Sortable option as a memory optimization.
 | |
| //
 | |
| // Deprecated: Use [NewSet] instead.
 | |
| func NewSetWithSortable(kvs []KeyValue, _ *Sortable) Set {
 | |
| 	s, _ := NewSetWithFiltered(kvs, nil)
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| // NewSetWithFiltered returns a new Set. See the documentation for
 | |
| // NewSetWithSortableFiltered for more details.
 | |
| //
 | |
| // This call includes a Filter to include/exclude attribute keys from the
 | |
| // return value. Excluded keys are returned as a slice of attribute values.
 | |
| func NewSetWithFiltered(kvs []KeyValue, filter Filter) (Set, []KeyValue) {
 | |
| 	// Check for empty set.
 | |
| 	if len(kvs) == 0 {
 | |
| 		return empty(), nil
 | |
| 	}
 | |
| 
 | |
| 	// Stable sort so the following de-duplication can implement
 | |
| 	// last-value-wins semantics.
 | |
| 	slices.SortStableFunc(kvs, func(a, b KeyValue) int {
 | |
| 		return cmp.Compare(a.Key, b.Key)
 | |
| 	})
 | |
| 
 | |
| 	position := len(kvs) - 1
 | |
| 	offset := position - 1
 | |
| 
 | |
| 	// The requirements stated above require that the stable
 | |
| 	// result be placed in the end of the input slice, while
 | |
| 	// overwritten values are swapped to the beginning.
 | |
| 	//
 | |
| 	// De-duplicate with last-value-wins semantics.  Preserve
 | |
| 	// duplicate values at the beginning of the input slice.
 | |
| 	for ; offset >= 0; offset-- {
 | |
| 		if kvs[offset].Key == kvs[position].Key {
 | |
| 			continue
 | |
| 		}
 | |
| 		position--
 | |
| 		kvs[offset], kvs[position] = kvs[position], kvs[offset]
 | |
| 	}
 | |
| 	kvs = kvs[position:]
 | |
| 
 | |
| 	if filter != nil {
 | |
| 		if div := filteredToFront(kvs, filter); div != 0 {
 | |
| 			return Set{equivalent: computeDistinct(kvs[div:])}, kvs[:div]
 | |
| 		}
 | |
| 	}
 | |
| 	return Set{equivalent: computeDistinct(kvs)}, nil
 | |
| }
 | |
| 
 | |
| // NewSetWithSortableFiltered returns a new Set.
 | |
| //
 | |
| // Duplicate keys are eliminated by taking the last value.  This
 | |
| // re-orders the input slice so that unique last-values are contiguous
 | |
| // at the end of the slice.
 | |
| //
 | |
| // This ensures the following:
 | |
| //
 | |
| // - Last-value-wins semantics
 | |
| // - Caller sees the reordering, but doesn't lose values
 | |
| // - Repeated call preserve last-value wins.
 | |
| //
 | |
| // Note that methods are defined on Set, although this returns Set. Callers
 | |
| // can avoid memory allocations by:
 | |
| //
 | |
| // - allocating a Sortable for use as a temporary in this method
 | |
| // - allocating a Set for storing the return value of this constructor.
 | |
| //
 | |
| // The result maintains a cache of encoded attributes, by attribute.EncoderID.
 | |
| // This value should not be copied after its first use.
 | |
| //
 | |
| // The second []KeyValue return value is a list of attributes that were
 | |
| // excluded by the Filter (if non-nil).
 | |
| //
 | |
| // Deprecated: Use [NewSetWithFiltered] instead.
 | |
| func NewSetWithSortableFiltered(kvs []KeyValue, _ *Sortable, filter Filter) (Set, []KeyValue) {
 | |
| 	return NewSetWithFiltered(kvs, filter)
 | |
| }
 | |
| 
 | |
| // filteredToFront filters slice in-place using keep function. All KeyValues that need to
 | |
| // be removed are moved to the front. All KeyValues that need to be kept are
 | |
| // moved (in-order) to the back. The index for the first KeyValue to be kept is
 | |
| // returned.
 | |
| func filteredToFront(slice []KeyValue, keep Filter) int {
 | |
| 	n := len(slice)
 | |
| 	j := n
 | |
| 	for i := n - 1; i >= 0; i-- {
 | |
| 		if keep(slice[i]) {
 | |
| 			j--
 | |
| 			slice[i], slice[j] = slice[j], slice[i]
 | |
| 		}
 | |
| 	}
 | |
| 	return j
 | |
| }
 | |
| 
 | |
| // Filter returns a filtered copy of this Set. See the documentation for
 | |
| // NewSetWithSortableFiltered for more details.
 | |
| func (l *Set) Filter(re Filter) (Set, []KeyValue) {
 | |
| 	if re == nil {
 | |
| 		return *l, nil
 | |
| 	}
 | |
| 
 | |
| 	// Iterate in reverse to the first attribute that will be filtered out.
 | |
| 	n := l.Len()
 | |
| 	first := n - 1
 | |
| 	for ; first >= 0; first-- {
 | |
| 		kv, _ := l.Get(first)
 | |
| 		if !re(kv) {
 | |
| 			break
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// No attributes will be dropped, return the immutable Set l and nil.
 | |
| 	if first < 0 {
 | |
| 		return *l, nil
 | |
| 	}
 | |
| 
 | |
| 	// Copy now that we know we need to return a modified set.
 | |
| 	//
 | |
| 	// Do not do this in-place on the underlying storage of *Set l. Sets are
 | |
| 	// immutable and filtering should not change this.
 | |
| 	slice := l.ToSlice()
 | |
| 
 | |
| 	// Don't re-iterate the slice if only slice[0] is filtered.
 | |
| 	if first == 0 {
 | |
| 		// It is safe to assume len(slice) >= 1 given we found at least one
 | |
| 		// attribute above that needs to be filtered out.
 | |
| 		return Set{equivalent: computeDistinct(slice[1:])}, slice[:1]
 | |
| 	}
 | |
| 
 | |
| 	// Move the filtered slice[first] to the front (preserving order).
 | |
| 	kv := slice[first]
 | |
| 	copy(slice[1:first+1], slice[:first])
 | |
| 	slice[0] = kv
 | |
| 
 | |
| 	// Do not re-evaluate re(slice[first+1:]).
 | |
| 	div := filteredToFront(slice[1:first+1], re) + 1
 | |
| 	return Set{equivalent: computeDistinct(slice[div:])}, slice[:div]
 | |
| }
 | |
| 
 | |
| // computeDistinct returns a Distinct using either the fixed- or
 | |
| // reflect-oriented code path, depending on the size of the input. The input
 | |
| // slice is assumed to already be sorted and de-duplicated.
 | |
| func computeDistinct(kvs []KeyValue) Distinct {
 | |
| 	iface := computeDistinctFixed(kvs)
 | |
| 	if iface == nil {
 | |
| 		iface = computeDistinctReflect(kvs)
 | |
| 	}
 | |
| 	return Distinct{
 | |
| 		iface: iface,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // computeDistinctFixed computes a Distinct for small slices. It returns nil
 | |
| // if the input is too large for this code path.
 | |
| func computeDistinctFixed(kvs []KeyValue) interface{} {
 | |
| 	switch len(kvs) {
 | |
| 	case 1:
 | |
| 		return [1]KeyValue(kvs)
 | |
| 	case 2:
 | |
| 		return [2]KeyValue(kvs)
 | |
| 	case 3:
 | |
| 		return [3]KeyValue(kvs)
 | |
| 	case 4:
 | |
| 		return [4]KeyValue(kvs)
 | |
| 	case 5:
 | |
| 		return [5]KeyValue(kvs)
 | |
| 	case 6:
 | |
| 		return [6]KeyValue(kvs)
 | |
| 	case 7:
 | |
| 		return [7]KeyValue(kvs)
 | |
| 	case 8:
 | |
| 		return [8]KeyValue(kvs)
 | |
| 	case 9:
 | |
| 		return [9]KeyValue(kvs)
 | |
| 	case 10:
 | |
| 		return [10]KeyValue(kvs)
 | |
| 	default:
 | |
| 		return nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // computeDistinctReflect computes a Distinct using reflection, works for any
 | |
| // size input.
 | |
| func computeDistinctReflect(kvs []KeyValue) interface{} {
 | |
| 	at := reflect.New(reflect.ArrayOf(len(kvs), keyValueType)).Elem()
 | |
| 	for i, keyValue := range kvs {
 | |
| 		*(at.Index(i).Addr().Interface().(*KeyValue)) = keyValue
 | |
| 	}
 | |
| 	return at.Interface()
 | |
| }
 | |
| 
 | |
| // MarshalJSON returns the JSON encoding of the Set.
 | |
| func (l *Set) MarshalJSON() ([]byte, error) {
 | |
| 	return json.Marshal(l.equivalent.iface)
 | |
| }
 | |
| 
 | |
| // MarshalLog is the marshaling function used by the logging system to represent this Set.
 | |
| func (l Set) MarshalLog() interface{} {
 | |
| 	kvs := make(map[string]string)
 | |
| 	for _, kv := range l.ToSlice() {
 | |
| 		kvs[string(kv.Key)] = kv.Value.Emit()
 | |
| 	}
 | |
| 	return kvs
 | |
| }
 | |
| 
 | |
| // Len implements sort.Interface.
 | |
| func (l *Sortable) Len() int {
 | |
| 	return len(*l)
 | |
| }
 | |
| 
 | |
| // Swap implements sort.Interface.
 | |
| func (l *Sortable) Swap(i, j int) {
 | |
| 	(*l)[i], (*l)[j] = (*l)[j], (*l)[i]
 | |
| }
 | |
| 
 | |
| // Less implements sort.Interface.
 | |
| func (l *Sortable) Less(i, j int) bool {
 | |
| 	return (*l)[i].Key < (*l)[j].Key
 | |
| }
 |