1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-01-07 23:02:15 +02:00
opentelemetry-go/api/tag/map.go
Krzesimir Nowak 670b0365d8 Make tag.Map a concrete type. (#89)
This is to make tag.Map an immutable type, so it is safe to use
concurrently. The safety is not yet fully achieved because of the
functions returning contents of the map (Value and Foreach). The
functions give callers an access to core.Value objects, which contain
a byte slice, which has pointer like semantics. So to avoid accidental
changes, we will need to copy the value if it is of BYTES type.

Fixes #59
2019-08-23 09:01:52 -07:00

133 lines
2.5 KiB
Go

// Copyright 2019, 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 tag
import (
"go.opentelemetry.io/api/core"
)
type MeasureMetadata struct {
TTL int // -1 == infinite, 0 == do not propagate
}
type tagContent struct {
value core.Value
meta MeasureMetadata
}
type rawMap map[core.Key]tagContent
type Map struct {
m rawMap
}
type MapUpdate struct {
SingleKV core.KeyValue
MultiKV []core.KeyValue
SingleMutator Mutator
MultiMutator []Mutator
}
func newMap(raw rawMap) Map {
return Map{
m: raw,
}
}
func NewEmptyMap() Map {
return newMap(nil)
}
func NewMap(update MapUpdate) Map {
return NewEmptyMap().Apply(update)
}
func (m Map) Apply(update MapUpdate) Map {
r := make(rawMap, len(m.m)+len(update.MultiKV)+len(update.MultiMutator))
for k, v := range m.m {
r[k] = v
}
if update.SingleKV.Key.Defined() {
r[update.SingleKV.Key] = tagContent{
value: update.SingleKV.Value,
}
}
for _, kv := range update.MultiKV {
r[kv.Key] = tagContent{
value: kv.Value,
}
}
if update.SingleMutator.Key.Defined() {
r.apply(update.SingleMutator)
}
for _, mutator := range update.MultiMutator {
r.apply(mutator)
}
if len(r) == 0 {
r = nil
}
return newMap(r)
}
func (m Map) Value(k core.Key) (core.Value, bool) {
entry, ok := m.m[k]
if !ok {
entry.value.Type = core.INVALID
}
return entry.value, ok
}
func (m Map) HasValue(k core.Key) bool {
_, has := m.Value(k)
return has
}
func (m Map) Len() int {
return len(m.m)
}
func (m Map) Foreach(f func(kv core.KeyValue) bool) {
for k, v := range m.m {
if !f(core.KeyValue{
Key: k,
Value: v.value,
}) {
return
}
}
}
func (r rawMap) apply(mutator Mutator) {
key := mutator.KeyValue.Key
content := tagContent{
value: mutator.KeyValue.Value,
meta: mutator.MeasureMetadata,
}
switch mutator.MutatorOp {
case INSERT:
if _, ok := r[key]; !ok {
r[key] = content
}
case UPDATE:
if _, ok := r[key]; ok {
r[key] = content
}
case UPSERT:
r[key] = content
case DELETE:
delete(r, key)
}
}