From bd061c738eafab5eaa7633a8f7dbc329d36726df Mon Sep 17 00:00:00 2001 From: Ian Cottrell Date: Tue, 14 Apr 2020 11:32:24 -0400 Subject: [PATCH] internal/telemetry: expose the TagOf* and Unpack* methods These allow tags to be constructed and used from outside the event package. This makes it easy for users of these APIs to write their own implementations of Key. Change-Id: Ic3320a80f297bbe1d4cd6d9beafbe13ebbace398 Reviewed-on: https://go-review.googlesource.com/c/tools/+/228232 Run-TryBot: Ian Cottrell TryBot-Result: Gobot Gobot Reviewed-by: Emmanuel Odeke --- internal/telemetry/event/event.go | 8 +- internal/telemetry/event/key.go | 79 +++++++++----------- internal/telemetry/event/tag.go | 53 +++++++++++-- internal/telemetry/export/log.go | 6 +- internal/telemetry/export/metric/exporter.go | 2 +- internal/telemetry/export/ocagent/ocagent.go | 4 +- 6 files changed, 91 insertions(+), 61 deletions(-) diff --git a/internal/telemetry/event/event.go b/internal/telemetry/event/event.go index 6028fa6d2b..2b990c5c1e 100644 --- a/internal/telemetry/event/event.go +++ b/internal/telemetry/event/event.go @@ -72,7 +72,7 @@ func (ev Event) Format(f fmt.State, r rune) { tag := ev.Tag(index) // msg and err were both already printed above, so we skip them to avoid // double printing - if !tag.Valid() || tag.Key == Msg || tag.Key == Err { + if !tag.Valid() || tag.Key() == Msg || tag.Key() == Err { continue } fmt.Fprintf(f, "\n\t%v", tag) @@ -90,14 +90,14 @@ func (ev Event) Tag(index int) Tag { return ev.dynamic[index-len(ev.static)] } -func (ev Event) Find(key interface{}) Tag { +func (ev Event) Find(key Key) Tag { for _, tag := range ev.static { - if tag.Key == key { + if tag.Key() == key { return tag } } for _, tag := range ev.dynamic { - if tag.Key == key { + if tag.Key() == key { return tag } } diff --git a/internal/telemetry/event/key.go b/internal/telemetry/event/key.go index 97572c37f1..503ec50dda 100644 --- a/internal/telemetry/event/key.go +++ b/internal/telemetry/event/key.go @@ -17,7 +17,9 @@ var ( Err = NewErrorKey("error", "an error that occurred") ) -// Key is the interface shared by all key implementations. +// Key is used as the identity of a Tag. +// Keys are intended to be compared by pointer only, the name should be unique +// for communicating with external systems, but it is not required or enforced. type Key interface { // Name returns the key name. Name() string @@ -25,14 +27,6 @@ type Key interface { Description() string } -// key is used as the identity of a Tag. -// Keys are intended to be compared by pointer only, the name should be unique -// for communicating with external systems, but it is not required or enforced. -type key struct { - name string - description string -} - // ValueKey represents a key for untyped values. type ValueKey struct { name string @@ -56,10 +50,10 @@ func (k *ValueKey) Get(tags TagMap) interface{} { } // From can be used to get a value from a Tag. -func (k *ValueKey) From(t Tag) interface{} { return t.untyped } +func (k *ValueKey) From(t Tag) interface{} { return t.UnpackValue() } // Of creates a new Tag with this key and the supplied value. -func (k *ValueKey) Of(value interface{}) Tag { return Tag{Key: k, untyped: value} } +func (k *ValueKey) Of(value interface{}) Tag { return TagOfValue(k, value) } // IntKey represents a key type IntKey struct { @@ -76,7 +70,7 @@ func (k *IntKey) Name() string { return k.name } func (k *IntKey) Description() string { return k.description } // Of creates a new Tag with this key and the supplied value. -func (k *IntKey) Of(v int) Tag { return Tag{Key: k, packed: uint64(v)} } +func (k *IntKey) Of(v int) Tag { return TagOf64(k, uint64(v)) } // Get can be used to get a tag for the key from a TagMap. func (k *IntKey) Get(tags TagMap) int { @@ -87,7 +81,7 @@ func (k *IntKey) Get(tags TagMap) int { } // From can be used to get a value from a Tag. -func (k *IntKey) From(t Tag) int { return int(t.packed) } +func (k *IntKey) From(t Tag) int { return int(t.Unpack64()) } // Int8Key represents a key type Int8Key struct { @@ -104,7 +98,7 @@ func (k *Int8Key) Name() string { return k.name } func (k *Int8Key) Description() string { return k.description } // Of creates a new Tag with this key and the supplied value. -func (k *Int8Key) Of(v int8) Tag { return Tag{Key: k, packed: uint64(v)} } +func (k *Int8Key) Of(v int8) Tag { return TagOf64(k, uint64(v)) } // Get can be used to get a tag for the key from a TagMap. func (k *Int8Key) Get(tags TagMap) int8 { @@ -115,7 +109,7 @@ func (k *Int8Key) Get(tags TagMap) int8 { } // From can be used to get a value from a Tag. -func (k *Int8Key) From(t Tag) int8 { return int8(t.packed) } +func (k *Int8Key) From(t Tag) int8 { return int8(t.Unpack64()) } // Int16Key represents a key type Int16Key struct { @@ -132,7 +126,7 @@ func (k *Int16Key) Name() string { return k.name } func (k *Int16Key) Description() string { return k.description } // Of creates a new Tag with this key and the supplied value. -func (k *Int16Key) Of(v int16) Tag { return Tag{Key: k, packed: uint64(v)} } +func (k *Int16Key) Of(v int16) Tag { return TagOf64(k, uint64(v)) } // Get can be used to get a tag for the key from a TagMap. func (k *Int16Key) Get(tags TagMap) int16 { @@ -143,7 +137,7 @@ func (k *Int16Key) Get(tags TagMap) int16 { } // From can be used to get a value from a Tag. -func (k *Int16Key) From(t Tag) int16 { return int16(t.packed) } +func (k *Int16Key) From(t Tag) int16 { return int16(t.Unpack64()) } // Int32Key represents a key type Int32Key struct { @@ -160,7 +154,7 @@ func (k *Int32Key) Name() string { return k.name } func (k *Int32Key) Description() string { return k.description } // Of creates a new Tag with this key and the supplied value. -func (k *Int32Key) Of(v int32) Tag { return Tag{Key: k, packed: uint64(v)} } +func (k *Int32Key) Of(v int32) Tag { return TagOf64(k, uint64(v)) } // Get can be used to get a tag for the key from a TagMap. func (k *Int32Key) Get(tags TagMap) int32 { @@ -171,7 +165,7 @@ func (k *Int32Key) Get(tags TagMap) int32 { } // From can be used to get a value from a Tag. -func (k *Int32Key) From(t Tag) int32 { return int32(t.packed) } +func (k *Int32Key) From(t Tag) int32 { return int32(t.Unpack64()) } // Int64Key represents a key type Int64Key struct { @@ -188,7 +182,7 @@ func (k *Int64Key) Name() string { return k.name } func (k *Int64Key) Description() string { return k.description } // Of creates a new Tag with this key and the supplied value. -func (k *Int64Key) Of(v int64) Tag { return Tag{Key: k, packed: uint64(v)} } +func (k *Int64Key) Of(v int64) Tag { return TagOf64(k, uint64(v)) } // Get can be used to get a tag for the key from a TagMap. func (k *Int64Key) Get(tags TagMap) int64 { @@ -199,7 +193,7 @@ func (k *Int64Key) Get(tags TagMap) int64 { } // From can be used to get a value from a Tag. -func (k *Int64Key) From(t Tag) int64 { return int64(t.packed) } +func (k *Int64Key) From(t Tag) int64 { return int64(t.Unpack64()) } // UIntKey represents a key type UIntKey struct { @@ -216,7 +210,7 @@ func (k *UIntKey) Name() string { return k.name } func (k *UIntKey) Description() string { return k.description } // Of creates a new Tag with this key and the supplied value. -func (k *UIntKey) Of(v uint) Tag { return Tag{Key: k, packed: uint64(v)} } +func (k *UIntKey) Of(v uint) Tag { return TagOf64(k, uint64(v)) } // Get can be used to get a tag for the key from a TagMap. func (k *UIntKey) Get(tags TagMap) uint { @@ -227,7 +221,7 @@ func (k *UIntKey) Get(tags TagMap) uint { } // From can be used to get a value from a Tag. -func (k *UIntKey) From(t Tag) uint { return uint(t.packed) } +func (k *UIntKey) From(t Tag) uint { return uint(t.Unpack64()) } // UInt8Key represents a key type UInt8Key struct { @@ -244,7 +238,7 @@ func (k *UInt8Key) Name() string { return k.name } func (k *UInt8Key) Description() string { return k.description } // Of creates a new Tag with this key and the supplied value. -func (k *UInt8Key) Of(v uint8) Tag { return Tag{Key: k, packed: uint64(v)} } +func (k *UInt8Key) Of(v uint8) Tag { return TagOf64(k, uint64(v)) } // Get can be used to get a tag for the key from a TagMap. func (k *UInt8Key) Get(tags TagMap) uint8 { @@ -255,7 +249,7 @@ func (k *UInt8Key) Get(tags TagMap) uint8 { } // From can be used to get a value from a Tag. -func (k *UInt8Key) From(t Tag) uint8 { return uint8(t.packed) } +func (k *UInt8Key) From(t Tag) uint8 { return uint8(t.Unpack64()) } // UInt16Key represents a key type UInt16Key struct { @@ -272,7 +266,7 @@ func (k *UInt16Key) Name() string { return k.name } func (k *UInt16Key) Description() string { return k.description } // Of creates a new Tag with this key and the supplied value. -func (k *UInt16Key) Of(v uint16) Tag { return Tag{Key: k, packed: uint64(v)} } +func (k *UInt16Key) Of(v uint16) Tag { return TagOf64(k, uint64(v)) } // Get can be used to get a tag for the key from a TagMap. func (k *UInt16Key) Get(tags TagMap) uint16 { @@ -283,7 +277,7 @@ func (k *UInt16Key) Get(tags TagMap) uint16 { } // From can be used to get a value from a Tag. -func (k *UInt16Key) From(t Tag) uint16 { return uint16(t.packed) } +func (k *UInt16Key) From(t Tag) uint16 { return uint16(t.Unpack64()) } // UInt32Key represents a key type UInt32Key struct { @@ -300,7 +294,7 @@ func (k *UInt32Key) Name() string { return k.name } func (k *UInt32Key) Description() string { return k.description } // Of creates a new Tag with this key and the supplied value. -func (k *UInt32Key) Of(v uint32) Tag { return Tag{Key: k, packed: uint64(v)} } +func (k *UInt32Key) Of(v uint32) Tag { return TagOf64(k, uint64(v)) } // Get can be used to get a tag for the key from a TagMap. func (k *UInt32Key) Get(tags TagMap) uint32 { @@ -311,7 +305,7 @@ func (k *UInt32Key) Get(tags TagMap) uint32 { } // From can be used to get a value from a Tag. -func (k *UInt32Key) From(t Tag) uint32 { return uint32(t.packed) } +func (k *UInt32Key) From(t Tag) uint32 { return uint32(t.Unpack64()) } // UInt64Key represents a key type UInt64Key struct { @@ -328,7 +322,7 @@ func (k *UInt64Key) Name() string { return k.name } func (k *UInt64Key) Description() string { return k.description } // Of creates a new Tag with this key and the supplied value. -func (k *UInt64Key) Of(v uint64) Tag { return Tag{Key: k, packed: v} } +func (k *UInt64Key) Of(v uint64) Tag { return TagOf64(k, v) } // Get can be used to get a tag for the key from a TagMap. func (k *UInt64Key) Get(tags TagMap) uint64 { @@ -339,7 +333,7 @@ func (k *UInt64Key) Get(tags TagMap) uint64 { } // From can be used to get a value from a Tag. -func (k *UInt64Key) From(t Tag) uint64 { return t.packed } +func (k *UInt64Key) From(t Tag) uint64 { return t.Unpack64() } // Float32Key represents a key type Float32Key struct { @@ -357,7 +351,7 @@ func (k *Float32Key) Description() string { return k.description } // Of creates a new Tag with this key and the supplied value. func (k *Float32Key) Of(v float32) Tag { - return Tag{Key: k, packed: uint64(math.Float32bits(v))} + return TagOf64(k, uint64(math.Float32bits(v))) } // Get can be used to get a tag for the key from a TagMap. @@ -370,7 +364,7 @@ func (k *Float32Key) Get(tags TagMap) float32 { // From can be used to get a value from a Tag. func (k *Float32Key) From(t Tag) float32 { - return math.Float32frombits(uint32(t.packed)) + return math.Float32frombits(uint32(t.Unpack64())) } // Float64Key represents a key @@ -389,7 +383,7 @@ func (k *Float64Key) Description() string { return k.description } // Of creates a new Tag with this key and the supplied value. func (k *Float64Key) Of(v float64) Tag { - return Tag{Key: k, packed: math.Float64bits(v)} + return TagOf64(k, math.Float64bits(v)) } // Get can be used to get a tag for the key from a TagMap. @@ -402,7 +396,7 @@ func (k *Float64Key) Get(tags TagMap) float64 { // From can be used to get a value from a Tag. func (k *Float64Key) From(t Tag) float64 { - return math.Float64frombits(t.packed) + return math.Float64frombits(t.Unpack64()) } // StringKey represents a key @@ -420,7 +414,7 @@ func (k *StringKey) Name() string { return k.name } func (k *StringKey) Description() string { return k.description } // Of creates a new Tag with this key and the supplied value. -func (k *StringKey) Of(v string) Tag { return Tag{Key: k, str: v} } +func (k *StringKey) Of(v string) Tag { return TagOfString(k, v) } // Get can be used to get a tag for the key from a TagMap. func (k *StringKey) Get(tags TagMap) string { @@ -431,7 +425,7 @@ func (k *StringKey) Get(tags TagMap) string { } // From can be used to get a value from a Tag. -func (k *StringKey) From(t Tag) string { return t.str } +func (k *StringKey) From(t Tag) string { return t.UnpackString() } // BooleanKey represents a key type BooleanKey struct { @@ -449,11 +443,10 @@ func (k *BooleanKey) Description() string { return k.description } // Of creates a new Tag with this key and the supplied value. func (k *BooleanKey) Of(v bool) Tag { - t := Tag{Key: k} if v { - t.packed = 1 + return TagOf64(k, 1) } - return t + return TagOf64(k, 0) } // Get can be used to get a tag for the key from a TagMap. @@ -465,7 +458,7 @@ func (k *BooleanKey) Get(tags TagMap) bool { } // From can be used to get a value from a Tag. -func (k *BooleanKey) From(t Tag) bool { return t.packed > 0 } +func (k *BooleanKey) From(t Tag) bool { return t.Unpack64() > 0 } // ErrorKey represents a key type ErrorKey struct { @@ -482,7 +475,7 @@ func (k *ErrorKey) Name() string { return k.name } func (k *ErrorKey) Description() string { return k.description } // Of creates a new Tag with this key and the supplied value. -func (k *ErrorKey) Of(v error) Tag { return Tag{Key: k, untyped: v} } +func (k *ErrorKey) Of(v error) Tag { return TagOfValue(k, v) } // Get can be used to get a tag for the key from a TagMap. func (k *ErrorKey) Get(tags TagMap) error { @@ -494,6 +487,6 @@ func (k *ErrorKey) Get(tags TagMap) error { // From can be used to get a value from a Tag. func (k *ErrorKey) From(t Tag) error { - err, _ := t.untyped.(error) + err, _ := t.UnpackValue().(error) return err } diff --git a/internal/telemetry/event/tag.go b/internal/telemetry/event/tag.go index 5fe40a1e9c..7381cd0b90 100644 --- a/internal/telemetry/event/tag.go +++ b/internal/telemetry/event/tag.go @@ -11,7 +11,7 @@ import ( // Tag holds a key and value pair. // It is normally used when passing around lists of tags. type Tag struct { - Key Key + key Key packed uint64 str string untyped interface{} @@ -20,7 +20,7 @@ type Tag struct { // TagMap is the interface to a collection of Tags indexed by key. type TagMap interface { // Find returns the tag that matches the supplied key. - Find(key interface{}) Tag + Find(key Key) Tag } // TagList is the interface to something that provides an iterable @@ -55,8 +55,45 @@ type tagMapChain struct { maps []TagMap } +// TagOfValue creates a new tag from the key and value. +// This method is for implementing new key types, tag creation should +// normally be done with the Of method of the key. +func TagOfValue(k Key, value interface{}) Tag { return Tag{key: k, untyped: value} } + +// UnpackValue assumes the tag was built using TagOfValue and returns the value +// that was passed to that constructor. +// This method is for implementing new key types, for type safety normal +// access should be done with the From method of the key. +func (t Tag) UnpackValue() interface{} { return t.untyped } + +// TagOf64 creates a new tag from a key and a uint64. This is often +// used for non uint64 values that can be packed into a uint64. +// This method is for implementing new key types, tag creation should +// normally be done with the Of method of the key. +func TagOf64(k Key, v uint64) Tag { return Tag{key: k, packed: v} } + +// Unpack64 assumes the tag was built using TagOf64 and returns the value that +// was passed to that constructor. +// This method is for implementing new key types, for type safety normal +// access should be done with the From method of the key. +func (t Tag) Unpack64() uint64 { return t.packed } + +// TagOfString creates a new tag from a key and a string. +// This method is for implementing new key types, tag creation should +// normally be done with the Of method of the key. +func TagOfString(k Key, v string) Tag { return Tag{key: k, str: v} } + +// UnpackString assumes the tag was built using TagOfString and returns the +// value that was passed to that constructor. +// This method is for implementing new key types, for type safety normal +// access should be done with the From method of the key. +func (t Tag) UnpackString() string { return t.str } + // Valid returns true if the Tag is a valid one (it has a key). -func (t Tag) Valid() bool { return t.Key != nil } +func (t Tag) Valid() bool { return t.key != nil } + +// Key returns the key of this Tag. +func (t Tag) Key() Key { return t.key } // Format is used for debug printing of tags. func (t Tag) Format(f fmt.State, r rune) { @@ -64,7 +101,7 @@ func (t Tag) Format(f fmt.State, r rune) { fmt.Fprintf(f, `nil`) return } - switch key := t.Key.(type) { + switch key := t.key.(type) { case *IntKey: fmt.Fprintf(f, "%s=%d", key.Name(), key.From(t)) case *Int8Key: @@ -117,23 +154,23 @@ func (f *tagFilter) Valid(index int) bool { func (f *tagFilter) Tag(index int) Tag { tag := f.underlying.Tag(index) for _, f := range f.keys { - if tag.Key == f { + if tag.Key() == f { return Tag{} } } return tag } -func (l tagMap) Find(key interface{}) Tag { +func (l tagMap) Find(key Key) Tag { for _, tag := range l.tags { - if tag.Key == key { + if tag.Key() == key { return tag } } return Tag{} } -func (c tagMapChain) Find(key interface{}) Tag { +func (c tagMapChain) Find(key Key) Tag { for _, src := range c.maps { tag := src.Find(key) if tag.Valid() { diff --git a/internal/telemetry/export/log.go b/internal/telemetry/export/log.go index f5278eddc3..525c80ef40 100644 --- a/internal/telemetry/export/log.go +++ b/internal/telemetry/export/log.go @@ -51,13 +51,13 @@ func (w *logWriter) ProcessEvent(ctx context.Context, ev event.Event, tagMap eve } for index := 0; ev.Valid(index); index++ { tag := ev.Tag(index) - if !tag.Valid() || tag.Key == event.Msg || tag.Key == event.Err { + if !tag.Valid() || tag.Key() == event.Msg || tag.Key() == event.Err { continue } io.WriteString(w.writer, "\n\t") - io.WriteString(w.writer, tag.Key.Name()) + io.WriteString(w.writer, tag.Key().Name()) io.WriteString(w.writer, "=") - switch key := tag.Key.(type) { + switch key := tag.Key().(type) { case *event.IntKey: w.writer.Write(strconv.AppendInt(buf, int64(key.From(tag)), 10)) case *event.Int8Key: diff --git a/internal/telemetry/export/metric/exporter.go b/internal/telemetry/export/metric/exporter.go index 56b4fa1609..ad3552fb44 100644 --- a/internal/telemetry/export/metric/exporter.go +++ b/internal/telemetry/export/metric/exporter.go @@ -42,7 +42,7 @@ func (e *Config) Exporter(output event.Exporter) event.Exporter { if !tag.Valid() { continue } - id := tag.Key + id := tag.Key() if list := e.subscribers[id]; len(list) > 0 { for _, s := range list { metrics = append(metrics, s(ev.At, tagMap, tag)) diff --git a/internal/telemetry/export/ocagent/ocagent.go b/internal/telemetry/export/ocagent/ocagent.go index 217ce9fb68..0d1af1aa38 100644 --- a/internal/telemetry/export/ocagent/ocagent.go +++ b/internal/telemetry/export/ocagent/ocagent.go @@ -245,7 +245,7 @@ func convertAttributes(l event.TagList) *wire.Attributes { attributes := make(map[string]wire.Attribute) for { if tag.Valid() { - attributes[tag.Key.Name()] = convertAttribute(tag) + attributes[tag.Key().Name()] = convertAttribute(tag) } index++ if !l.Valid(index) { @@ -256,7 +256,7 @@ func convertAttributes(l event.TagList) *wire.Attributes { } func convertAttribute(tag event.Tag) wire.Attribute { - switch key := tag.Key.(type) { + switch key := tag.Key().(type) { case *event.IntKey: return wire.IntAttribute{IntValue: int64(key.From(tag))} case *event.Int8Key: