[VOL-3860] redis client support in voltha-lib-go

redis client support has been added in this patch. There are two
types client `redis` and `redis-sentinel` to connect a redis instance.
redis-sentinel is required to be able to find the master redis
instance from a redis-sentinel process. See redis-sentinel usage
https://redis.io/topics/sentinel and
https://pkg.go.dev/github.com/go-redis/redis/v8#NewFailoverClient
for more information. If there is no need to have any failover
mechanism then the redis client type is the option to choose.

Change-Id: I997ed92115a9d565df632c6dd8184b9bab77b991
diff --git a/vendor/go.opentelemetry.io/otel/label/doc.go b/vendor/go.opentelemetry.io/otel/label/doc.go
new file mode 100644
index 0000000..d631d23
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/label/doc.go
@@ -0,0 +1,16 @@
+// 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 label provides key and value labels.
+package label // import "go.opentelemetry.io/otel/label"
diff --git a/vendor/go.opentelemetry.io/otel/label/encoder.go b/vendor/go.opentelemetry.io/otel/label/encoder.go
new file mode 100644
index 0000000..6be7a3f
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/label/encoder.go
@@ -0,0 +1,150 @@
+// 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 label
+
+import (
+	"bytes"
+	"sync"
+	"sync/atomic"
+)
+
+type (
+	// Encoder is a mechanism for serializing a label set into a
+	// specific string representation that supports caching, to
+	// avoid repeated serialization. An example could be an
+	// exporter encoding the label set into a wire representation.
+	Encoder interface {
+		// Encode returns the serialized encoding of the label
+		// set using its Iterator.  This result may be cached
+		// by a label.Set.
+		Encode(iterator Iterator) string
+
+		// ID returns a value that is unique for each class of
+		// label encoder.  Label encoders allocate these using
+		// `NewEncoderID`.
+		ID() EncoderID
+	}
+
+	// EncoderID is used to identify distinct Encoder
+	// implementations, for caching encoded results.
+	EncoderID struct {
+		value uint64
+	}
+
+	// defaultLabelEncoder uses a sync.Pool of buffers to reduce
+	// the number of allocations used in encoding labels.  This
+	// implementation encodes a comma-separated list of key=value,
+	// with '/'-escaping of '=', ',', and '\'.
+	defaultLabelEncoder struct {
+		// pool is a pool of labelset builders.  The buffers in this
+		// pool grow to a size that most label encodings will not
+		// allocate new memory.
+		pool sync.Pool // *bytes.Buffer
+	}
+)
+
+// escapeChar is used to ensure uniqueness of the label encoding where
+// keys or values contain either '=' or ','.  Since there is no parser
+// needed for this encoding and its only requirement is to be unique,
+// this choice is arbitrary.  Users will see these in some exporters
+// (e.g., stdout), so the backslash ('\') is used as a conventional choice.
+const escapeChar = '\\'
+
+var (
+	_ Encoder = &defaultLabelEncoder{}
+
+	// encoderIDCounter is for generating IDs for other label
+	// encoders.
+	encoderIDCounter uint64
+
+	defaultEncoderOnce     sync.Once
+	defaultEncoderID       = NewEncoderID()
+	defaultEncoderInstance *defaultLabelEncoder
+)
+
+// NewEncoderID returns a unique label encoder ID. It should be
+// called once per each type of label encoder. Preferably in init() or
+// in var definition.
+func NewEncoderID() EncoderID {
+	return EncoderID{value: atomic.AddUint64(&encoderIDCounter, 1)}
+}
+
+// DefaultEncoder returns a label encoder that encodes labels
+// in such a way that each escaped label's key is followed by an equal
+// sign and then by an escaped label's value. All key-value pairs are
+// separated by a comma.
+//
+// Escaping is done by prepending a backslash before either a
+// backslash, equal sign or a comma.
+func DefaultEncoder() Encoder {
+	defaultEncoderOnce.Do(func() {
+		defaultEncoderInstance = &defaultLabelEncoder{
+			pool: sync.Pool{
+				New: func() interface{} {
+					return &bytes.Buffer{}
+				},
+			},
+		}
+	})
+	return defaultEncoderInstance
+}
+
+// Encode is a part of an implementation of the LabelEncoder
+// interface.
+func (d *defaultLabelEncoder) Encode(iter Iterator) string {
+	buf := d.pool.Get().(*bytes.Buffer)
+	defer d.pool.Put(buf)
+	buf.Reset()
+
+	for iter.Next() {
+		i, keyValue := iter.IndexedLabel()
+		if i > 0 {
+			_, _ = buf.WriteRune(',')
+		}
+		copyAndEscape(buf, string(keyValue.Key))
+
+		_, _ = buf.WriteRune('=')
+
+		if keyValue.Value.Type() == STRING {
+			copyAndEscape(buf, keyValue.Value.AsString())
+		} else {
+			_, _ = buf.WriteString(keyValue.Value.Emit())
+		}
+	}
+	return buf.String()
+}
+
+// ID is a part of an implementation of the LabelEncoder interface.
+func (*defaultLabelEncoder) ID() EncoderID {
+	return defaultEncoderID
+}
+
+// copyAndEscape escapes `=`, `,` and its own escape character (`\`),
+// making the default encoding unique.
+func copyAndEscape(buf *bytes.Buffer, val string) {
+	for _, ch := range val {
+		switch ch {
+		case '=', ',', escapeChar:
+			buf.WriteRune(escapeChar)
+		}
+		buf.WriteRune(ch)
+	}
+}
+
+// Valid returns true if this encoder ID was allocated by
+// `NewEncoderID`.  Invalid encoder IDs will not be cached.
+func (id EncoderID) Valid() bool {
+	return id.value != 0
+}
diff --git a/vendor/go.opentelemetry.io/otel/label/iterator.go b/vendor/go.opentelemetry.io/otel/label/iterator.go
new file mode 100644
index 0000000..9e72239
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/label/iterator.go
@@ -0,0 +1,143 @@
+// 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 label
+
+// Iterator allows iterating over the set of labels in order,
+// sorted by key.
+type Iterator struct {
+	storage *Set
+	idx     int
+}
+
+// MergeIterator supports iterating over two sets of labels while
+// eliminating duplicate values from the combined set.  The first
+// iterator value takes precedence.
+type MergeItererator struct {
+	one     oneIterator
+	two     oneIterator
+	current KeyValue
+}
+
+type oneIterator struct {
+	iter  Iterator
+	done  bool
+	label KeyValue
+}
+
+// Next moves the iterator to the next position. Returns false if there
+// are no more labels.
+func (i *Iterator) Next() bool {
+	i.idx++
+	return i.idx < i.Len()
+}
+
+// Label returns current KeyValue. Must be called only after Next returns
+// true.
+func (i *Iterator) Label() KeyValue {
+	kv, _ := i.storage.Get(i.idx)
+	return kv
+}
+
+// Attribute is a synonym for Label().
+func (i *Iterator) Attribute() KeyValue {
+	return i.Label()
+}
+
+// IndexedLabel returns current index and label. Must be called only
+// after Next returns true.
+func (i *Iterator) IndexedLabel() (int, KeyValue) {
+	return i.idx, i.Label()
+}
+
+// Len returns a number of labels in the iterator's `*Set`.
+func (i *Iterator) Len() int {
+	return i.storage.Len()
+}
+
+// ToSlice is a convenience function that creates a slice of labels
+// from the passed iterator. The iterator is set up to start from the
+// beginning before creating the slice.
+func (i *Iterator) ToSlice() []KeyValue {
+	l := i.Len()
+	if l == 0 {
+		return nil
+	}
+	i.idx = -1
+	slice := make([]KeyValue, 0, l)
+	for i.Next() {
+		slice = append(slice, i.Label())
+	}
+	return slice
+}
+
+// NewMergeIterator returns a MergeIterator for merging two label sets
+// Duplicates are resolved by taking the value from the first set.
+func NewMergeIterator(s1, s2 *Set) MergeItererator {
+	mi := MergeItererator{
+		one: makeOne(s1.Iter()),
+		two: makeOne(s2.Iter()),
+	}
+	return mi
+}
+
+func makeOne(iter Iterator) oneIterator {
+	oi := oneIterator{
+		iter: iter,
+	}
+	oi.advance()
+	return oi
+}
+
+func (oi *oneIterator) advance() {
+	if oi.done = !oi.iter.Next(); !oi.done {
+		oi.label = oi.iter.Label()
+	}
+}
+
+// Next returns true if there is another label available.
+func (m *MergeItererator) Next() bool {
+	if m.one.done && m.two.done {
+		return false
+	}
+	if m.one.done {
+		m.current = m.two.label
+		m.two.advance()
+		return true
+	}
+	if m.two.done {
+		m.current = m.one.label
+		m.one.advance()
+		return true
+	}
+	if m.one.label.Key == m.two.label.Key {
+		m.current = m.one.label // first iterator label value wins
+		m.one.advance()
+		m.two.advance()
+		return true
+	}
+	if m.one.label.Key < m.two.label.Key {
+		m.current = m.one.label
+		m.one.advance()
+		return true
+	}
+	m.current = m.two.label
+	m.two.advance()
+	return true
+}
+
+// Label returns the current value after Next() returns true.
+func (m *MergeItererator) Label() KeyValue {
+	return m.current
+}
diff --git a/vendor/go.opentelemetry.io/otel/label/key.go b/vendor/go.opentelemetry.io/otel/label/key.go
new file mode 100644
index 0000000..7d72378
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/label/key.go
@@ -0,0 +1,169 @@
+// 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 label
+
+// Key represents the key part in key-value pairs. It's a string. The
+// allowed character set in the key depends on the use of the key.
+type Key string
+
+// Bool creates a KeyValue instance with a BOOL Value.
+//
+// If creating both key and a bool value at the same time, then
+// instead of calling Key(name).Bool(value) consider using a
+// convenience function provided by the api/key package -
+// key.Bool(name, value).
+func (k Key) Bool(v bool) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: BoolValue(v),
+	}
+}
+
+// Int64 creates a KeyValue instance with an INT64 Value.
+//
+// If creating both key and an int64 value at the same time, then
+// instead of calling Key(name).Int64(value) consider using a
+// convenience function provided by the api/key package -
+// key.Int64(name, value).
+func (k Key) Int64(v int64) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: Int64Value(v),
+	}
+}
+
+// Uint64 creates a KeyValue instance with a UINT64 Value.
+//
+// If creating both key and a uint64 value at the same time, then
+// instead of calling Key(name).Uint64(value) consider using a
+// convenience function provided by the api/key package -
+// key.Uint64(name, value).
+func (k Key) Uint64(v uint64) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: Uint64Value(v),
+	}
+}
+
+// Float64 creates a KeyValue instance with a FLOAT64 Value.
+//
+// If creating both key and a float64 value at the same time, then
+// instead of calling Key(name).Float64(value) consider using a
+// convenience function provided by the api/key package -
+// key.Float64(name, value).
+func (k Key) Float64(v float64) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: Float64Value(v),
+	}
+}
+
+// Int32 creates a KeyValue instance with an INT32 Value.
+//
+// If creating both key and an int32 value at the same time, then
+// instead of calling Key(name).Int32(value) consider using a
+// convenience function provided by the api/key package -
+// key.Int32(name, value).
+func (k Key) Int32(v int32) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: Int32Value(v),
+	}
+}
+
+// Uint32 creates a KeyValue instance with a UINT32 Value.
+//
+// If creating both key and a uint32 value at the same time, then
+// instead of calling Key(name).Uint32(value) consider using a
+// convenience function provided by the api/key package -
+// key.Uint32(name, value).
+func (k Key) Uint32(v uint32) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: Uint32Value(v),
+	}
+}
+
+// Float32 creates a KeyValue instance with a FLOAT32 Value.
+//
+// If creating both key and a float32 value at the same time, then
+// instead of calling Key(name).Float32(value) consider using a
+// convenience function provided by the api/key package -
+// key.Float32(name, value).
+func (k Key) Float32(v float32) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: Float32Value(v),
+	}
+}
+
+// String creates a KeyValue instance with a STRING Value.
+//
+// If creating both key and a string value at the same time, then
+// instead of calling Key(name).String(value) consider using a
+// convenience function provided by the api/key package -
+// key.String(name, value).
+func (k Key) String(v string) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: StringValue(v),
+	}
+}
+
+// Int creates a KeyValue instance with either an INT32 or an INT64
+// Value, depending on whether the int type is 32 or 64 bits wide.
+//
+// If creating both key and an int value at the same time, then
+// instead of calling Key(name).Int(value) consider using a
+// convenience function provided by the api/key package -
+// key.Int(name, value).
+func (k Key) Int(v int) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: IntValue(v),
+	}
+}
+
+// Uint creates a KeyValue instance with either a UINT32 or a UINT64
+// Value, depending on whether the uint type is 32 or 64 bits wide.
+//
+// If creating both key and a uint value at the same time, then
+// instead of calling Key(name).Uint(value) consider using a
+// convenience function provided by the api/key package -
+// key.Uint(name, value).
+func (k Key) Uint(v uint) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: UintValue(v),
+	}
+}
+
+// Defined returns true for non-empty keys.
+func (k Key) Defined() bool {
+	return len(k) != 0
+}
+
+// Array creates a KeyValue instance with a ARRAY Value.
+//
+// If creating both key and a array value at the same time, then
+// instead of calling Key(name).String(value) consider using a
+// convenience function provided by the api/key package -
+// key.Array(name, value).
+func (k Key) Array(v interface{}) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: ArrayValue(v),
+	}
+}
diff --git a/vendor/go.opentelemetry.io/otel/label/kv.go b/vendor/go.opentelemetry.io/otel/label/kv.go
new file mode 100644
index 0000000..3e2764f
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/label/kv.go
@@ -0,0 +1,144 @@
+// 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 label
+
+import (
+	"encoding/json"
+	"fmt"
+	"reflect"
+)
+
+// KeyValue holds a key and value pair.
+type KeyValue struct {
+	Key   Key
+	Value Value
+}
+
+// Bool creates a new key-value pair with a passed name and a bool
+// value.
+func Bool(k string, v bool) KeyValue {
+	return Key(k).Bool(v)
+}
+
+// Int64 creates a new key-value pair with a passed name and an int64
+// value.
+func Int64(k string, v int64) KeyValue {
+	return Key(k).Int64(v)
+}
+
+// Uint64 creates a new key-value pair with a passed name and a uint64
+// value.
+func Uint64(k string, v uint64) KeyValue {
+	return Key(k).Uint64(v)
+}
+
+// Float64 creates a new key-value pair with a passed name and a float64
+// value.
+func Float64(k string, v float64) KeyValue {
+	return Key(k).Float64(v)
+}
+
+// Int32 creates a new key-value pair with a passed name and an int32
+// value.
+func Int32(k string, v int32) KeyValue {
+	return Key(k).Int32(v)
+}
+
+// Uint32 creates a new key-value pair with a passed name and a uint32
+// value.
+func Uint32(k string, v uint32) KeyValue {
+	return Key(k).Uint32(v)
+}
+
+// Float32 creates a new key-value pair with a passed name and a float32
+// value.
+func Float32(k string, v float32) KeyValue {
+	return Key(k).Float32(v)
+}
+
+// String creates a new key-value pair with a passed name and a string
+// value.
+func String(k, v string) KeyValue {
+	return Key(k).String(v)
+}
+
+// Stringer creates a new key-value pair with a passed name and a string
+// value generated by the passed Stringer interface.
+func Stringer(k string, v fmt.Stringer) KeyValue {
+	return Key(k).String(v.String())
+}
+
+// Int creates a new key-value pair instance with a passed name and
+// either an int32 or an int64 value, depending on whether the int
+// type is 32 or 64 bits wide.
+func Int(k string, v int) KeyValue {
+	return Key(k).Int(v)
+}
+
+// Uint creates a new key-value pair instance with a passed name and
+// either an uint32 or an uint64 value, depending on whether the uint
+// type is 32 or 64 bits wide.
+func Uint(k string, v uint) KeyValue {
+	return Key(k).Uint(v)
+}
+
+// Array creates a new key-value pair with a passed name and a array.
+// Only arrays of primitive type are supported.
+func Array(k string, v interface{}) KeyValue {
+	return Key(k).Array(v)
+}
+
+// Any creates a new key-value pair instance with a passed name and
+// automatic type inference. This is slower, and not type-safe.
+func Any(k string, value interface{}) KeyValue {
+	if value == nil {
+		return String(k, "<nil>")
+	}
+
+	if stringer, ok := value.(fmt.Stringer); ok {
+		return String(k, stringer.String())
+	}
+
+	rv := reflect.ValueOf(value)
+
+	switch rv.Kind() {
+	case reflect.Array, reflect.Slice:
+		return Array(k, value)
+	case reflect.Bool:
+		return Bool(k, rv.Bool())
+	case reflect.Int, reflect.Int8, reflect.Int16:
+		return Int(k, int(rv.Int()))
+	case reflect.Int32:
+		return Int32(k, int32(rv.Int()))
+	case reflect.Int64:
+		return Int64(k, int64(rv.Int()))
+	case reflect.Uint, reflect.Uint8, reflect.Uint16:
+		return Uint(k, uint(rv.Uint()))
+	case reflect.Uint32:
+		return Uint32(k, uint32(rv.Uint()))
+	case reflect.Uint64, reflect.Uintptr:
+		return Uint64(k, rv.Uint())
+	case reflect.Float32:
+		return Float32(k, float32(rv.Float()))
+	case reflect.Float64:
+		return Float64(k, rv.Float())
+	case reflect.String:
+		return String(k, rv.String())
+	}
+	if b, err := json.Marshal(value); value != nil && err == nil {
+		return String(k, string(b))
+	}
+	return String(k, fmt.Sprint(value))
+}
diff --git a/vendor/go.opentelemetry.io/otel/label/set.go b/vendor/go.opentelemetry.io/otel/label/set.go
new file mode 100644
index 0000000..3bd5263
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/label/set.go
@@ -0,0 +1,468 @@
+// 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 label
+
+import (
+	"encoding/json"
+	"reflect"
+	"sort"
+	"sync"
+)
+
+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
+
+		lock     sync.Mutex
+		encoders [maxConcurrentEncoders]EncoderID
+		encoded  [maxConcurrentEncoders]string
+	}
+
+	// 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{},
+		},
+	}
+)
+
+const maxConcurrentEncoders = 3
+
+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`.  The result will be cached in this `*Set`.
+func (l *Set) Encoded(encoder Encoder) string {
+	if l == nil || encoder == nil {
+		return ""
+	}
+
+	id := encoder.ID()
+	if !id.Valid() {
+		// Invalid IDs are not cached.
+		return encoder.Encode(l.Iter())
+	}
+
+	var lookup *string
+	l.lock.Lock()
+	for idx := 0; idx < maxConcurrentEncoders; idx++ {
+		if l.encoders[idx] == id {
+			lookup = &l.encoded[idx]
+			break
+		}
+	}
+	l.lock.Unlock()
+
+	if lookup != nil {
+		return *lookup
+	}
+
+	r := encoder.Encode(l.Iter())
+
+	l.lock.Lock()
+	defer l.lock.Unlock()
+
+	for idx := 0; idx < maxConcurrentEncoders; idx++ {
+		if l.encoders[idx] == id {
+			return l.encoded[idx]
+		}
+		if !l.encoders[idx].Valid() {
+			l.encoders[idx] = id
+			l.encoded[idx] = r
+			return r
+		}
+	}
+
+	// TODO: This is a performance cliff.  Find a way for this to
+	// generate a warning.
+	return r
+}
+
+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 //nolint
+}
+
+// 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 //nolint
+}
+
+// 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 label.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
+}
diff --git a/vendor/go.opentelemetry.io/otel/label/type_string.go b/vendor/go.opentelemetry.io/otel/label/type_string.go
new file mode 100644
index 0000000..62afeb6
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/label/type_string.go
@@ -0,0 +1,32 @@
+// Code generated by "stringer -type=Type"; DO NOT EDIT.
+
+package label
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[INVALID-0]
+	_ = x[BOOL-1]
+	_ = x[INT32-2]
+	_ = x[INT64-3]
+	_ = x[UINT32-4]
+	_ = x[UINT64-5]
+	_ = x[FLOAT32-6]
+	_ = x[FLOAT64-7]
+	_ = x[STRING-8]
+	_ = x[ARRAY-9]
+}
+
+const _Type_name = "INVALIDBOOLINT32INT64UINT32UINT64FLOAT32FLOAT64STRINGARRAY"
+
+var _Type_index = [...]uint8{0, 7, 11, 16, 21, 27, 33, 40, 47, 53, 58}
+
+func (i Type) String() string {
+	if i < 0 || i >= Type(len(_Type_index)-1) {
+		return "Type(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _Type_name[_Type_index[i]:_Type_index[i+1]]
+}
diff --git a/vendor/go.opentelemetry.io/otel/label/value.go b/vendor/go.opentelemetry.io/otel/label/value.go
new file mode 100644
index 0000000..679009b
--- /dev/null
+++ b/vendor/go.opentelemetry.io/otel/label/value.go
@@ -0,0 +1,288 @@
+// 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 label
+
+import (
+	"encoding/json"
+	"fmt"
+	"reflect"
+	"strconv"
+	"unsafe"
+
+	"go.opentelemetry.io/otel/internal"
+)
+
+//go:generate stringer -type=Type
+
+// Type describes the type of the data Value holds.
+type Type int
+
+// Value represents the value part in key-value pairs.
+type Value struct {
+	vtype    Type
+	numeric  uint64
+	stringly string
+	// TODO Lazy value type?
+
+	array interface{}
+}
+
+const (
+	INVALID Type = iota // No value.
+	BOOL                // Boolean value, use AsBool() to get it.
+	INT32               // 32 bit signed integral value, use AsInt32() to get it.
+	INT64               // 64 bit signed integral value, use AsInt64() to get it.
+	UINT32              // 32 bit unsigned integral value, use AsUint32() to get it.
+	UINT64              // 64 bit unsigned integral value, use AsUint64() to get it.
+	FLOAT32             // 32 bit floating point value, use AsFloat32() to get it.
+	FLOAT64             // 64 bit floating point value, use AsFloat64() to get it.
+	STRING              // String value, use AsString() to get it.
+	ARRAY               // Array value of arbitrary type, use AsArray() to get it.
+)
+
+// BoolValue creates a BOOL Value.
+func BoolValue(v bool) Value {
+	return Value{
+		vtype:   BOOL,
+		numeric: internal.BoolToRaw(v),
+	}
+}
+
+// Int64Value creates an INT64 Value.
+func Int64Value(v int64) Value {
+	return Value{
+		vtype:   INT64,
+		numeric: internal.Int64ToRaw(v),
+	}
+}
+
+// Uint64Value creates a UINT64 Value.
+func Uint64Value(v uint64) Value {
+	return Value{
+		vtype:   UINT64,
+		numeric: internal.Uint64ToRaw(v),
+	}
+}
+
+// Float64Value creates a FLOAT64 Value.
+func Float64Value(v float64) Value {
+	return Value{
+		vtype:   FLOAT64,
+		numeric: internal.Float64ToRaw(v),
+	}
+}
+
+// Int32Value creates an INT32 Value.
+func Int32Value(v int32) Value {
+	return Value{
+		vtype:   INT32,
+		numeric: internal.Int32ToRaw(v),
+	}
+}
+
+// Uint32Value creates a UINT32 Value.
+func Uint32Value(v uint32) Value {
+	return Value{
+		vtype:   UINT32,
+		numeric: internal.Uint32ToRaw(v),
+	}
+}
+
+// Float32Value creates a FLOAT32 Value.
+func Float32Value(v float32) Value {
+	return Value{
+		vtype:   FLOAT32,
+		numeric: internal.Float32ToRaw(v),
+	}
+}
+
+// StringValue creates a STRING Value.
+func StringValue(v string) Value {
+	return Value{
+		vtype:    STRING,
+		stringly: v,
+	}
+}
+
+// IntValue creates either an INT32 or an INT64 Value, depending on whether
+// the int type is 32 or 64 bits wide.
+func IntValue(v int) Value {
+	if unsafe.Sizeof(v) == 4 {
+		return Int32Value(int32(v))
+	}
+	return Int64Value(int64(v))
+}
+
+// UintValue creates either a UINT32 or a UINT64 Value, depending on whether
+// the uint type is 32 or 64 bits wide.
+func UintValue(v uint) Value {
+	if unsafe.Sizeof(v) == 4 {
+		return Uint32Value(uint32(v))
+	}
+	return Uint64Value(uint64(v))
+}
+
+// ArrayValue creates an ARRAY value from an array or slice.
+// Only arrays or slices of bool, int, int32, int64, uint, uint32, uint64,
+// float, float32, float64, or string types are allowed. Specifically, arrays
+// and slices can not contain other arrays, slices, structs, or non-standard
+// types. If the passed value is not an array or slice of these types an
+// INVALID value is returned.
+func ArrayValue(v interface{}) Value {
+	switch reflect.TypeOf(v).Kind() {
+	case reflect.Array, reflect.Slice:
+		// get array type regardless of dimensions
+		typ := reflect.TypeOf(v).Elem()
+		kind := typ.Kind()
+		switch kind {
+		case reflect.Bool, reflect.Int, reflect.Int32, reflect.Int64,
+			reflect.Float32, reflect.Float64, reflect.String,
+			reflect.Uint, reflect.Uint32, reflect.Uint64:
+			val := reflect.ValueOf(v)
+			length := val.Len()
+			frozen := reflect.Indirect(reflect.New(reflect.ArrayOf(length, typ)))
+			reflect.Copy(frozen, val)
+			return Value{
+				vtype: ARRAY,
+				array: frozen.Interface(),
+			}
+		default:
+			return Value{vtype: INVALID}
+		}
+	}
+	return Value{vtype: INVALID}
+}
+
+// Type returns a type of the Value.
+func (v Value) Type() Type {
+	return v.vtype
+}
+
+// AsBool returns the bool value. Make sure that the Value's type is
+// BOOL.
+func (v Value) AsBool() bool {
+	return internal.RawToBool(v.numeric)
+}
+
+// AsInt32 returns the int32 value. Make sure that the Value's type is
+// INT32.
+func (v Value) AsInt32() int32 {
+	return internal.RawToInt32(v.numeric)
+}
+
+// AsInt64 returns the int64 value. Make sure that the Value's type is
+// INT64.
+func (v Value) AsInt64() int64 {
+	return internal.RawToInt64(v.numeric)
+}
+
+// AsUint32 returns the uint32 value. Make sure that the Value's type
+// is UINT32.
+func (v Value) AsUint32() uint32 {
+	return internal.RawToUint32(v.numeric)
+}
+
+// AsUint64 returns the uint64 value. Make sure that the Value's type is
+// UINT64.
+func (v Value) AsUint64() uint64 {
+	return internal.RawToUint64(v.numeric)
+}
+
+// AsFloat32 returns the float32 value. Make sure that the Value's
+// type is FLOAT32.
+func (v Value) AsFloat32() float32 {
+	return internal.RawToFloat32(v.numeric)
+}
+
+// AsFloat64 returns the float64 value. Make sure that the Value's
+// type is FLOAT64.
+func (v Value) AsFloat64() float64 {
+	return internal.RawToFloat64(v.numeric)
+}
+
+// AsString returns the string value. Make sure that the Value's type
+// is STRING.
+func (v Value) AsString() string {
+	return v.stringly
+}
+
+// AsArray returns the array Value as an interface{}.
+func (v Value) AsArray() interface{} {
+	return v.array
+}
+
+type unknownValueType struct{}
+
+// AsInterface returns Value's data as interface{}.
+func (v Value) AsInterface() interface{} {
+	switch v.Type() {
+	case ARRAY:
+		return v.AsArray()
+	case BOOL:
+		return v.AsBool()
+	case INT32:
+		return v.AsInt32()
+	case INT64:
+		return v.AsInt64()
+	case UINT32:
+		return v.AsUint32()
+	case UINT64:
+		return v.AsUint64()
+	case FLOAT32:
+		return v.AsFloat32()
+	case FLOAT64:
+		return v.AsFloat64()
+	case STRING:
+		return v.stringly
+	}
+	return unknownValueType{}
+}
+
+// Emit returns a string representation of Value's data.
+func (v Value) Emit() string {
+	switch v.Type() {
+	case ARRAY:
+		return fmt.Sprint(v.array)
+	case BOOL:
+		return strconv.FormatBool(v.AsBool())
+	case INT32:
+		return strconv.FormatInt(int64(v.AsInt32()), 10)
+	case INT64:
+		return strconv.FormatInt(v.AsInt64(), 10)
+	case UINT32:
+		return strconv.FormatUint(uint64(v.AsUint32()), 10)
+	case UINT64:
+		return strconv.FormatUint(v.AsUint64(), 10)
+	case FLOAT32:
+		return fmt.Sprint(v.AsFloat32())
+	case FLOAT64:
+		return fmt.Sprint(v.AsFloat64())
+	case STRING:
+		return v.stringly
+	default:
+		return "unknown"
+	}
+}
+
+// MarshalJSON returns the JSON encoding of the Value.
+func (v Value) MarshalJSON() ([]byte, error) {
+	var jsonVal struct {
+		Type  string
+		Value interface{}
+	}
+	jsonVal.Type = v.Type().String()
+	jsonVal.Value = v.AsInterface()
+	return json.Marshal(jsonVal)
+}