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 <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
This commit is contained in:
Ian Cottrell 2020-04-14 11:32:24 -04:00
parent 5d8e1897c7
commit bd061c738e
6 changed files with 91 additions and 61 deletions

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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() {

View File

@ -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:

View File

@ -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))

View File

@ -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: