123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- // Copyright The OpenTelemetry Authors
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package attribute // import "go.opentelemetry.io/otel/attribute"
- import (
- "encoding/json"
- "reflect"
- "sort"
- )
- type (
- // Set is the representation for a distinct label set. It
- // manages an immutable set of labels, with an internal cache
- // for storing label encodings.
- //
- // This type supports the `Equivalent` method of comparison
- // using values of type `Distinct`.
- //
- // This type is used to implement:
- // 1. Metric labels
- // 2. Resource sets
- // 3. Correlation map (TODO)
- Set struct {
- equivalent Distinct
- }
- // Distinct wraps a variable-size array of `KeyValue`,
- // constructed with keys in sorted order. This can be used as
- // a map key or for equality checking between Sets.
- Distinct struct {
- iface interface{}
- }
- // Filter supports removing certain labels from label sets.
- // When the filter returns true, the label will be kept in
- // the filtered label set. When the filter returns false, the
- // label is excluded from the filtered label set, and the
- // label instead appears in the `removed` list of excluded labels.
- Filter func(KeyValue) bool
- // Sortable implements `sort.Interface`, used for sorting
- // `KeyValue`. This is an exported type to support a
- // memory optimization. A pointer to one of these is needed
- // for the call to `sort.Stable()`, which the caller may
- // provide in order to avoid an allocation. See
- // `NewSetWithSortable()`.
- Sortable []KeyValue
- )
- var (
- // keyValueType is used in `computeDistinctReflect`.
- keyValueType = reflect.TypeOf(KeyValue{})
- // emptySet is returned for empty label 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
- }
- // reflect abbreviates `reflect.ValueOf`.
- func (d Distinct) reflect() reflect.Value {
- return reflect.ValueOf(d.iface)
- }
- // Valid returns true if this value refers to a valid `*Set`.
- func (d Distinct) Valid() bool {
- return d.iface != nil
- }
- // Len returns the number of labels in this set.
- func (l *Set) Len() int {
- if l == nil || !l.equivalent.Valid() {
- return 0
- }
- return l.equivalent.reflect().Len()
- }
- // Get returns the KeyValue at ordered position `idx` in this set.
- func (l *Set) Get(idx int) (KeyValue, bool) {
- if l == nil {
- return KeyValue{}, false
- }
- value := l.equivalent.reflect()
- 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 {
- return Value{}, false
- }
- rValue := l.equivalent.reflect()
- 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 tests 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 labels in this set.
- func (l *Set) Iter() Iterator {
- return Iterator{
- storage: l,
- idx: -1,
- }
- }
- // ToSlice returns the set of labels 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 label 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 returns true if 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 {
- // Check for empty set.
- if len(kvs) == 0 {
- return empty()
- }
- s, _ := NewSetWithSortableFiltered(kvs, new(Sortable), 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.
- func NewSetWithSortable(kvs []KeyValue, tmp *Sortable) Set {
- // Check for empty set.
- if len(kvs) == 0 {
- return empty()
- }
- s, _ := NewSetWithSortableFiltered(kvs, tmp, nil)
- return s
- }
- // NewSetWithFiltered returns a new `Set`. See the documentation for
- // `NewSetWithSortableFiltered` for more details.
- //
- // This call includes a `Filter` to include/exclude label keys from
- // the return value. Excluded keys are returned as a slice of label
- // values.
- func NewSetWithFiltered(kvs []KeyValue, filter Filter) (Set, []KeyValue) {
- // Check for empty set.
- if len(kvs) == 0 {
- return empty(), nil
- }
- return NewSetWithSortableFiltered(kvs, new(Sortable), filter)
- }
- // 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 labels, by attribute.EncoderID.
- // This value should not be copied after its first use.
- //
- // The second `[]KeyValue` return value is a list of labels that were
- // excluded by the Filter (if non-nil).
- func NewSetWithSortableFiltered(kvs []KeyValue, tmp *Sortable, filter Filter) (Set, []KeyValue) {
- // Check for empty set.
- if len(kvs) == 0 {
- return empty(), nil
- }
- *tmp = kvs
- // Stable sort so the following de-duplication can implement
- // last-value-wins semantics.
- sort.Stable(tmp)
- *tmp = nil
- 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]
- }
- if filter != nil {
- return filterSet(kvs[position:], filter)
- }
- return Set{
- equivalent: computeDistinct(kvs[position:]),
- }, nil
- }
- // filterSet reorders `kvs` so that included keys are contiguous at
- // the end of the slice, while excluded keys precede the included keys.
- func filterSet(kvs []KeyValue, filter Filter) (Set, []KeyValue) {
- var excluded []KeyValue
- // Move labels that do not match the filter so
- // they're adjacent before calling computeDistinct().
- distinctPosition := len(kvs)
- // Swap indistinct keys forward and distinct keys toward the
- // end of the slice.
- offset := len(kvs) - 1
- for ; offset >= 0; offset-- {
- if filter(kvs[offset]) {
- distinctPosition--
- kvs[offset], kvs[distinctPosition] = kvs[distinctPosition], kvs[offset]
- continue
- }
- }
- excluded = kvs[:distinctPosition]
- return Set{
- equivalent: computeDistinct(kvs[distinctPosition:]),
- }, excluded
- }
- // 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 Set{
- equivalent: l.equivalent,
- }, nil
- }
- // Note: This could be refactored to avoid the temporary slice
- // allocation, if it proves to be expensive.
- return filterSet(l.ToSlice(), re)
- }
- // 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:
- ptr := new([1]KeyValue)
- copy((*ptr)[:], kvs)
- return *ptr
- case 2:
- ptr := new([2]KeyValue)
- copy((*ptr)[:], kvs)
- return *ptr
- case 3:
- ptr := new([3]KeyValue)
- copy((*ptr)[:], kvs)
- return *ptr
- case 4:
- ptr := new([4]KeyValue)
- copy((*ptr)[:], kvs)
- return *ptr
- case 5:
- ptr := new([5]KeyValue)
- copy((*ptr)[:], kvs)
- return *ptr
- case 6:
- ptr := new([6]KeyValue)
- copy((*ptr)[:], kvs)
- return *ptr
- case 7:
- ptr := new([7]KeyValue)
- copy((*ptr)[:], kvs)
- return *ptr
- case 8:
- ptr := new([8]KeyValue)
- copy((*ptr)[:], kvs)
- return *ptr
- case 9:
- ptr := new([9]KeyValue)
- copy((*ptr)[:], kvs)
- return *ptr
- case 10:
- ptr := new([10]KeyValue)
- copy((*ptr)[:], kvs)
- return *ptr
- 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)
- }
- // 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
- }
|