internal/telemetry: add type safe tag keys

This changes the way keys work, there is still a single internal key
implementation for performance reasons, but the public interface is a set of key
implementations that have type safe Of and Get methods.
This also hides the implemenation of Tag so that we can modify the storage form
and find a more efficient storage if needed.

Change-Id: I6a39cc75c2824c6a92e52d59f16e82e876f16e9c
Reviewed-on: https://go-review.googlesource.com/c/tools/+/223137
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-03-10 23:52:14 -04:00
Родитель d7fc2cf50e
Коммит 540150da73
24 изменённых файлов: 438 добавлений и 110 удалений

2
internal/lsp/cache/analysis.go поставляемый
Просмотреть файл

@ -207,7 +207,7 @@ func runAnalysis(ctx context.Context, fset *token.FileSet, analyzer *analysis.An
}
defer func() {
if r := recover(); r != nil {
event.Print(ctx, fmt.Sprintf("analysis panicked: %s", r), tag.Package.Of(pkg.PkgPath))
event.Print(ctx, fmt.Sprintf("analysis panicked: %s", r), tag.Package.Of(pkg.PkgPath()))
data.err = errors.Errorf("analysis %s for package %s panicked: %v", analyzer.Name, pkg.PkgPath(), r)
}
}()

4
internal/lsp/cache/check.go поставляемый
Просмотреть файл

@ -143,7 +143,7 @@ func (s *snapshot) buildKey(ctx context.Context, id packageID, mode source.Parse
}
depHandle, err := s.buildPackageHandle(ctx, depID, mode)
if err != nil {
event.Error(ctx, "no dep handle", err, tag.Package.Of(depID))
event.Error(ctx, "no dep handle", err, tag.Package.Of(string(depID)))
// One bad dependency should not prevent us from checking the entire package.
// Add a special key to mark a bad dependency.
@ -259,7 +259,7 @@ func (s *snapshot) parseGoHandles(ctx context.Context, files []span.URI, mode so
}
func typeCheck(ctx context.Context, fset *token.FileSet, m *metadata, mode source.ParseMode, goFiles []source.ParseGoHandle, compiledGoFiles []source.ParseGoHandle, deps map[packagePath]*packageHandle) (*pkg, error) {
ctx, done := event.StartSpan(ctx, "cache.importer.typeCheck", tag.Package.Of(m.id))
ctx, done := event.StartSpan(ctx, "cache.importer.typeCheck", tag.Package.Of(string(m.id)))
defer done()
var rawErrors []error

4
internal/lsp/cache/mod.go поставляемый
Просмотреть файл

@ -144,7 +144,7 @@ func (s *snapshot) ModHandle(ctx context.Context, fh source.FileHandle) source.M
view: folder,
}
h := s.view.session.cache.store.Bind(key, func(ctx context.Context) interface{} {
ctx, done := event.StartSpan(ctx, "cache.ModHandle", tag.File.Of(uri))
ctx, done := event.StartSpan(ctx, "cache.ModHandle", tag.URI.Of(uri))
defer done()
contents, _, err := fh.Read(ctx)
@ -317,7 +317,7 @@ func (s *snapshot) ModTidyHandle(ctx context.Context, realfh source.FileHandle)
return &modData{}
}
ctx, done := event.StartSpan(ctx, "cache.ModTidyHandle", tag.File.Of(realURI))
ctx, done := event.StartSpan(ctx, "cache.ModTidyHandle", tag.URI.Of(realURI))
defer done()
realContents, _, err := realfh.Read(ctx)

2
internal/lsp/cache/snapshot.go поставляемый
Просмотреть файл

@ -151,7 +151,7 @@ func (s *snapshot) PackageHandles(ctx context.Context, fh source.FileHandle) ([]
panic("called PackageHandles on a non-Go FileHandle")
}
ctx = event.Label(ctx, tag.File.Of(fh.Identity().URI))
ctx = event.Label(ctx, tag.URI.Of(fh.Identity().URI))
// Check if we should reload metadata for the file. We don't invalidate IDs
// (though we should), so the IDs will be a better source of truth than the

Просмотреть файл

@ -73,7 +73,7 @@ func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionPara
// First, add the quick fixes reported by go/analysis.
qf, err := quickFixes(ctx, snapshot, fh, diagnostics)
if err != nil {
event.Error(ctx, "quick fixes failed", err, tag.File.Of(uri))
event.Error(ctx, "quick fixes failed", err, tag.URI.Of(uri))
}
codeActions = append(codeActions, qf...)
@ -97,7 +97,7 @@ func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionPara
}
actions, err := mod.SuggestedGoFixes(ctx, snapshot, fh, diagnostics)
if err != nil {
event.Error(ctx, "quick fixes failed", err, tag.File.Of(uri))
event.Error(ctx, "quick fixes failed", err, tag.URI.Of(uri))
}
if len(actions) > 0 {
codeActions = append(codeActions, actions...)

Просмотреть файл

@ -30,7 +30,7 @@ func (s *Server) completion(ctx context.Context, params *protocol.CompletionPara
}
if err != nil {
event.Print(ctx, "no completions found", tag.Position.Of(params.Position), event.Err.Of("Failure"))
event.Print(ctx, "no completions found", tag.Position.Of(params.Position), event.Err.Of(err))
}
if candidates == nil {
return &protocol.CompletionList{

Просмотреть файл

@ -18,33 +18,33 @@ var (
receivedBytes = metric.HistogramInt64{
Name: "received_bytes",
Description: "Distribution of received bytes, by method.",
Keys: []*event.Key{tag.RPCDirection, tag.Method},
Keys: []event.Key{tag.RPCDirection, tag.Method},
Buckets: bytesDistribution,
}.Record(tag.ReceivedBytes)
sentBytes = metric.HistogramInt64{
Name: "sent_bytes",
Description: "Distribution of sent bytes, by method.",
Keys: []*event.Key{tag.RPCDirection, tag.Method},
Keys: []event.Key{tag.RPCDirection, tag.Method},
Buckets: bytesDistribution,
}.Record(tag.SentBytes)
latency = metric.HistogramFloat64{
Name: "latency",
Description: "Distribution of latency in milliseconds, by method.",
Keys: []*event.Key{tag.RPCDirection, tag.Method},
Keys: []event.Key{tag.RPCDirection, tag.Method},
Buckets: millisecondsDistribution,
}.Record(tag.Latency)
started = metric.Scalar{
Name: "started",
Description: "Count of RPCs started by method.",
Keys: []*event.Key{tag.RPCDirection, tag.Method},
Keys: []event.Key{tag.RPCDirection, tag.Method},
}.CountInt64(tag.Started)
completed = metric.Scalar{
Name: "completed",
Description: "Count of RPCs completed by method and status.",
Keys: []*event.Key{tag.RPCDirection, tag.Method, tag.StatusCode},
Keys: []event.Key{tag.RPCDirection, tag.Method, tag.StatusCode},
}.CountFloat64(tag.Latency)
)

Просмотреть файл

@ -8,7 +8,6 @@ import (
"context"
"fmt"
"html/template"
"log"
"net/http"
"sort"
"sync"
@ -97,13 +96,10 @@ func (r *rpcs) Metric(ctx context.Context, data event.MetricData) {
defer r.mu.Unlock()
for i, group := range data.Groups() {
set := &r.Inbound
if group.Get(tag.RPCDirection) == tag.Outbound {
if tag.RPCDirection.Get(group) == tag.Outbound {
set = &r.Outbound
}
method, ok := group.Get(tag.Method).(string)
if !ok {
continue
}
method := tag.Method.Get(group)
index := sort.Search(len(*set), func(i int) bool {
return (*set)[i].Method >= method
})
@ -119,11 +115,7 @@ func (r *rpcs) Metric(ctx context.Context, data event.MetricData) {
case started:
stats.Started = data.(*metric.Int64Data).Rows[i]
case completed:
status, ok := group.Get(tag.StatusCode).(string)
if !ok {
log.Printf("Not status... %v", group)
continue
}
status := tag.StatusCode.Get(group)
var b *rpcCodeBucket
for c, entry := range stats.Codes {
if entry.Key == status {

Просмотреть файл

@ -13,27 +13,27 @@ import (
var (
// create the tag keys we use
Method = &event.Key{Name: "method"}
StatusCode = &event.Key{Name: "status.code"}
StatusMessage = &event.Key{Name: "status.message"}
RPCID = &event.Key{Name: "id"}
RPCDirection = &event.Key{Name: "direction"}
File = &event.Key{Name: "file"}
Directory = &event.Key{Name: "directory"}
URI = &event.Key{Name: "URI"}
Package = &event.Key{Name: "package"}
PackagePath = &event.Key{Name: "package_path"}
Query = &event.Key{Name: "query"}
Snapshot = &event.Key{Name: "snapshot"}
Operation = &event.Key{Name: "operation"}
Method = event.NewStringKey("method", "")
StatusCode = event.NewStringKey("status.code", "")
StatusMessage = event.NewStringKey("status.message", "")
RPCID = event.NewStringKey("id", "")
RPCDirection = event.NewStringKey("direction", "")
File = event.NewStringKey("file", "")
Directory = event.NewKey("directory", "")
URI = event.NewKey("URI", "")
Package = event.NewStringKey("package", "")
PackagePath = event.NewStringKey("package_path", "")
Query = event.NewKey("query", "")
Snapshot = event.NewUInt64Key("snapshot", "")
Operation = event.NewStringKey("operation", "")
Position = &event.Key{Name: "position"}
Category = &event.Key{Name: "category"}
PackageCount = &event.Key{Name: "packages"}
Files = &event.Key{Name: "files"}
Port = &event.Key{Name: "port"}
Type = &event.Key{Name: "type"}
HoverKind = &event.Key{Name: "hoverkind"}
Position = event.NewKey("position", "")
Category = event.NewStringKey("category", "")
PackageCount = event.NewIntKey("packages", "")
Files = event.NewKey("files", "")
Port = event.NewIntKey("port", "")
Type = event.NewKey("type", "")
HoverKind = event.NewStringKey("hoverkind", "")
)
var (

Просмотреть файл

@ -172,7 +172,7 @@ func fillOffsets(td *traceData, start time.Time) {
func renderTags(tags event.TagList) string {
buf := &bytes.Buffer{}
for _, tag := range tags {
fmt.Fprintf(buf, "%v=%q ", tag.Key, tag.Value)
fmt.Fprintf(buf, "%s=%q ", tag.Key().Name(), tag.Value())
}
return buf.String()
}

Просмотреть файл

@ -46,7 +46,7 @@ func (h telemetryHandler) Request(ctx context.Context, conn *jsonrpc2.Conn, dire
ctx, stats.close = event.StartSpan(ctx, r.Method,
tag.Method.Of(r.Method),
tag.RPCDirection.Of(mode),
tag.RPCID.Of(r.ID),
tag.RPCID.Of(r.ID.String()),
)
tag.Started.Record(ctx, 1)
_, stats.delivering = event.StartSpan(ctx, "queued")

Просмотреть файл

@ -22,7 +22,7 @@ func CodeLens(ctx context.Context, snapshot source.Snapshot, uri span.URI) ([]pr
if uri != realURI {
return nil, nil
}
ctx, done := event.StartSpan(ctx, "mod.CodeLens", tag.File.Of(realURI))
ctx, done := event.StartSpan(ctx, "mod.CodeLens", tag.URI.Of(realURI))
defer done()
fh, err := snapshot.GetFile(realURI)

Просмотреть файл

@ -27,7 +27,7 @@ func Diagnostics(ctx context.Context, snapshot source.Snapshot) (map[source.File
return nil, nil, nil
}
ctx, done := event.StartSpan(ctx, "mod.Diagnostics", tag.File.Of(realURI))
ctx, done := event.StartSpan(ctx, "mod.Diagnostics", tag.URI.Of(realURI))
defer done()
realfh, err := snapshot.GetFile(realURI)
@ -126,7 +126,7 @@ func SuggestedGoFixes(ctx context.Context, snapshot source.Snapshot, gofh source
return nil, nil
}
ctx, done := event.StartSpan(ctx, "mod.SuggestedGoFixes", tag.File.Of(realURI))
ctx, done := event.StartSpan(ctx, "mod.SuggestedGoFixes", tag.URI.Of(realURI))
defer done()
realfh, err := snapshot.GetFile(realURI)

Просмотреть файл

@ -18,8 +18,8 @@ type Hooks struct {
}
var (
aValue = &event.Key{Name: "a"}
bValue = &event.Key{Name: "b"}
aValue = event.NewInt64Key("a", "")
bValue = event.NewStringKey("b", "")
aCount = stats.Int64("aCount", "Count of time A is called.", unit.Dimensionless)
aStat = stats.Int64("aValue", "A value.", unit.Dimensionless)
bCount = stats.Int64("B", "Count of time B is called.", unit.Dimensionless)
@ -51,9 +51,9 @@ var (
Log = Hooks{
A: func(ctx context.Context, a *int) (context.Context, func()) {
event.Print(ctx, "start A", aValue.Of(*a))
event.Print(ctx, "start A", aValue.Of(int64(*a)))
return ctx, func() {
event.Print(ctx, "end A", aValue.Of(*a))
event.Print(ctx, "end A", aValue.Of(int64(*a)))
}
},
B: func(ctx context.Context, b *string) (context.Context, func()) {

Просмотреть файл

@ -49,6 +49,6 @@ func (e Event) Format(f fmt.State, r rune) {
}
}
for _, tag := range e.Tags {
fmt.Fprintf(f, "\n\t%s = %v", tag.Key.Name, tag.Value)
fmt.Fprintf(f, "\n\t%s = %v", tag.key.name, tag.value)
}
}

Просмотреть файл

@ -6,19 +6,335 @@ package event
var (
// Err is a key used to add error values to tag lists.
Err = Key{Name: "error"}
Err = NewErrorKey("error", "")
)
// Key is used as the identity of a Tag.
// Key is the interface shared by all key implementations.
type Key interface {
// Identity returns the underlying key identity.
Identity() interface{}
// Name returns the key name.
Name() string
// Description returns a string that can be used to describe the value.
Description() string
// OfValue creates a new Tag with this key and the supplied untyped value.
OfValue(interface{}) Tag
}
// 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
type key struct {
name string
description string
}
func newKey(name, description string) *key { return &key{name: name, description: description} }
func (k *key) Name() string { return k.name }
func (k *key) Description() string { return k.description }
func (k *key) Identity() interface{} { return k }
func (k *key) OfValue(value interface{}) Tag { return Tag{key: k, value: value} }
// ValueKey represents a key for untyped values.
type ValueKey struct{ *key }
// NewKey creates a new Key for untyped values.
func NewKey(name, description string) ValueKey {
return ValueKey{newKey(name, description)}
}
// Get can be used to get a tag for the key from a TagList.
func (k ValueKey) Get(tags TagList) interface{} {
if t := tags.find(k.key); t.key != nil {
return t.value
}
return nil
}
// Of creates a new Tag with this key and the supplied value.
// You can use this when building a tag list.
func (k *Key) Of(v interface{}) Tag {
return Tag{Key: k, Value: v}
func (k ValueKey) Of(value interface{}) Tag { return Tag{key: k.key, value: value} }
// IntKey represents a key
type IntKey struct{ *key }
// NewIntKey creates a new Key for int values.
func NewIntKey(name, description string) IntKey {
return IntKey{newKey(name, description)}
}
// Of creates a new Tag with this key and the supplied value.
func (k IntKey) Of(v int) Tag { return Tag{key: k.key, value: v} }
// Get can be used to get a tag for the key from a TagList.
func (k IntKey) Get(tags TagList) int {
if t := tags.find(k.key); t.key != nil {
return t.value.(int)
}
return 0
}
// Int8Key represents a key
type Int8Key struct{ *key }
// NewInt8Key creates a new Key for int8 values.
func NewInt8Key(name, description string) Int8Key {
return Int8Key{newKey(name, description)}
}
// Of creates a new Tag with this key and the supplied value.
func (k Int8Key) Of(v int8) Tag { return Tag{key: k.key, value: v} }
// Get can be used to get a tag for the key from a TagList.
func (k Int8Key) Get(tags TagList) int8 {
if t := tags.find(k.key); t.key != nil {
return t.value.(int8)
}
return 0
}
// Int16Key represents a key
type Int16Key struct{ *key }
// NewInt16Key creates a new Key for int16 values.
func NewInt16Key(name, description string) Int16Key {
return Int16Key{newKey(name, description)}
}
// Of creates a new Tag with this key and the supplied value.
func (k Int16Key) Of(v int16) Tag { return Tag{key: k.key, value: v} }
// Get can be used to get a tag for the key from a TagList.
func (k Int16Key) Get(tags TagList) int16 {
if t := tags.find(k.key); t.key != nil {
return t.value.(int16)
}
return 0
}
// Int32Key represents a key
type Int32Key struct{ *key }
// NewInt32Key creates a new Key for int32 values.
func NewInt32Key(name, description string) Int32Key {
return Int32Key{newKey(name, description)}
}
// Of creates a new Tag with this key and the supplied value.
func (k Int32Key) Of(v int32) Tag { return Tag{key: k.key, value: v} }
// Get can be used to get a tag for the key from a TagList.
func (k Int32Key) Get(tags TagList) int32 {
if t := tags.find(k.key); t.key != nil {
return t.value.(int32)
}
return 0
}
// Int64Key represents a key
type Int64Key struct{ *key }
// NewInt64Key creates a new Key for int64 values.
func NewInt64Key(name, description string) Int64Key {
return Int64Key{newKey(name, description)}
}
// Of creates a new Tag with this key and the supplied value.
func (k Int64Key) Of(v int64) Tag { return Tag{key: k.key, value: v} }
// Get can be used to get a tag for the key from a TagList.
func (k Int64Key) Get(tags TagList) int64 {
if t := tags.find(k.key); t.key != nil {
return t.value.(int64)
}
return 0
}
// UIntKey represents a key
type UIntKey struct{ *key }
// NewUIntKey creates a new Key for uint values.
func NewUIntKey(name, description string) UIntKey {
return UIntKey{newKey(name, description)}
}
// Of creates a new Tag with this key and the supplied value.
func (k UIntKey) Of(v uint) Tag { return Tag{key: k.key, value: v} }
// Get can be used to get a tag for the key from a TagList.
func (k UIntKey) Get(tags TagList) uint {
if t := tags.find(k.key); t.key != nil {
return t.value.(uint)
}
return 0
}
// UInt8Key represents a key
type UInt8Key struct{ *key }
// NewUInt8Key creates a new Key for uint8 values.
func NewUInt8Key(name, description string) UInt8Key {
return UInt8Key{newKey(name, description)}
}
// Of creates a new Tag with this key and the supplied value.
func (k UInt8Key) Of(v uint8) Tag { return Tag{key: k.key, value: v} }
// Get can be used to get a tag for the key from a TagList.
func (k UInt8Key) Get(tags TagList) uint8 {
if t := tags.find(k.key); t.key != nil {
return t.value.(uint8)
}
return 0
}
// UInt16Key represents a key
type UInt16Key struct{ *key }
// NewUInt16Key creates a new Key for uint16 values.
func NewUInt16Key(name, description string) UInt16Key {
return UInt16Key{newKey(name, description)}
}
// Of creates a new Tag with this key and the supplied value.
func (k UInt16Key) Of(v uint16) Tag { return Tag{key: k.key, value: v} }
// Get can be used to get a tag for the key from a TagList.
func (k UInt16Key) Get(tags TagList) uint16 {
if t := tags.find(k.key); t.key != nil {
return t.value.(uint16)
}
return 0
}
// UInt32Key represents a key
type UInt32Key struct{ *key }
// NewUInt32Key creates a new Key for uint32 values.
func NewUInt32Key(name, description string) UInt32Key {
return UInt32Key{newKey(name, description)}
}
// Of creates a new Tag with this key and the supplied value.
func (k UInt32Key) Of(v uint32) Tag { return Tag{key: k.key, value: v} }
// Get can be used to get a tag for the key from a TagList.
func (k UInt32Key) Get(tags TagList) uint32 {
if t := tags.find(k.key); t.key != nil {
return t.value.(uint32)
}
return 0
}
// UInt64Key represents a key
type UInt64Key struct{ *key }
// NewUInt64Key creates a new Key for uint64 values.
func NewUInt64Key(name, description string) UInt64Key {
return UInt64Key{newKey(name, description)}
}
// Of creates a new Tag with this key and the supplied value.
func (k UInt64Key) Of(v uint64) Tag { return Tag{key: k.key, value: v} }
// Get can be used to get a tag for the key from a TagList.
func (k UInt64Key) Get(tags TagList) uint64 {
if t := tags.find(k.key); t.key != nil {
return t.value.(uint64)
}
return 0
}
// Float32Key represents a key
type Float32Key struct{ *key }
// NewFloat32Key creates a new Key for float32 values.
func NewFloat32Key(name, description string) Float32Key {
return Float32Key{newKey(name, description)}
}
// Of creates a new Tag with this key and the supplied value.
func (k Float32Key) Of(v float32) Tag { return Tag{key: k.key, value: v} }
// Get can be used to get a tag for the key from a TagList.
func (k Float32Key) Get(tags TagList) float32 {
if t := tags.find(k.key); t.key != nil {
return t.value.(float32)
}
return 0
}
// Float64Key represents a key
type Float64Key struct{ *key }
// NewFloat64Key creates a new Key for int64 values.
func NewFloat64Key(name, description string) Float64Key {
return Float64Key{newKey(name, description)}
}
// Of creates a new Tag with this key and the supplied value.
func (k Float64Key) Of(v float64) Tag { return Tag{key: k.key, value: v} }
// Get can be used to get a tag for the key from a TagList.
func (k Float64Key) Get(tags TagList) float64 {
if t := tags.find(k.key); t.key != nil {
return t.value.(float64)
}
return 0
}
// StringKey represents a key
type StringKey struct{ *key }
// NewStringKey creates a new Key for int64 values.
func NewStringKey(name, description string) StringKey {
return StringKey{newKey(name, description)}
}
// Of creates a new Tag with this key and the supplied value.
func (k StringKey) Of(v string) Tag { return Tag{key: k.key, value: v} }
// Get can be used to get a tag for the key from a TagList.
func (k StringKey) Get(tags TagList) string {
if t := tags.find(k.key); t.key != nil {
return t.value.(string)
}
return ""
}
// BooleanKey represents a key
type BooleanKey struct{ *key }
// NewBooleanKey creates a new Key for bool values.
func NewBooleanKey(name, description string) BooleanKey {
return BooleanKey{newKey(name, description)}
}
// Of creates a new Tag with this key and the supplied value.
func (k BooleanKey) Of(v bool) Tag { return Tag{key: k.key, value: v} }
// Get can be used to get a tag for the key from a TagList.
func (k BooleanKey) Get(tags TagList) bool {
if t := tags.find(k.key); t.key != nil {
return t.value.(bool)
}
return false
}
// ErrorKey represents a key
type ErrorKey struct{ *key }
// NewErrorKey creates a new Key for int64 values.
func NewErrorKey(name, description string) ErrorKey {
return ErrorKey{newKey(name, description)}
}
// Of creates a new Tag with this key and the supplied value.
func (k ErrorKey) Of(v error) Tag { return Tag{key: k.key, value: v} }
// Get can be used to get a tag for the key from a TagList.
func (k ErrorKey) Get(tags TagList) error {
if t := tags.find(k.key); t.key != nil {
return t.value.(error)
}
return nil
}

Просмотреть файл

@ -21,10 +21,10 @@ func Label(ctx context.Context, tags ...Tag) context.Context {
// Query sends a query event to the exporter with the supplied keys.
// The returned tags will have up to date values if the exporter supports it.
func Query(ctx context.Context, keys ...*Key) TagList {
func Query(ctx context.Context, keys ...Key) TagList {
tags := make(TagList, len(keys))
for i, k := range keys {
tags[i].Key = k
tags[i] = k.OfValue(nil)
}
_, ev := ProcessEvent(ctx, Event{
Type: QueryType,

Просмотреть файл

@ -11,8 +11,8 @@ import (
// Tag holds a key and value pair.
// It is normally used when passing around lists of tags.
type Tag struct {
Key *Key
Value interface{}
key *key
value interface{}
}
// TagList is a way of passing around a collection of key value pairs.
@ -20,19 +20,39 @@ type Tag struct {
// maps.
type TagList []Tag
// Key returns the key for this Tag.
func (t Tag) Key() Key { return t.key }
// Value returns the value for this Tag.
func (t Tag) Value() interface{} { return t.value }
// Format is used for debug printing of tags.
func (t Tag) Format(f fmt.State, r rune) {
fmt.Fprintf(f, `%v="%v"`, t.Key.Name, t.Value)
if t.key == nil {
fmt.Fprintf(f, `nil`)
return
}
fmt.Fprintf(f, `%v="%v"`, t.key.name, t.value)
}
// Get will get a single key's value from the list.
func (l TagList) Get(k interface{}) interface{} {
// FindAll returns corresponding tags for each key in keys.
// If no tag is found for a key, the Tag at its corresponding
// index will be of the zero value.
func (l TagList) FindAll(keys []Key) TagList {
tags := make(TagList, len(keys))
for i, key := range keys {
tags[i] = l.find(key.Identity())
}
return tags
}
func (l TagList) find(key interface{}) Tag {
for _, t := range l {
if t.Key == k {
return t.Value
if t.key == key {
return t
}
}
return nil
return Tag{}
}
// Format pretty prints a list.
@ -40,7 +60,7 @@ func (l TagList) Get(k interface{}) interface{} {
func (l TagList) Format(f fmt.State, r rune) {
printed := false
for _, t := range l {
if t.Value == nil {
if t.value == nil {
continue
}
if printed {

Просмотреть файл

@ -5,7 +5,6 @@
package ocagent
import (
"fmt"
"time"
"golang.org/x/tools/internal/telemetry/event"
@ -202,11 +201,11 @@ func distributionToPoints(counts []int64, count int64, sum float64, bucketBounds
// infoKeysToLabelKeys returns an array of *wire.LabelKeys containing the
// string values of the elements of labelKeys.
func infoKeysToLabelKeys(infoKeys []*event.Key) []*wire.LabelKey {
func infoKeysToLabelKeys(infoKeys []event.Key) []*wire.LabelKey {
labelKeys := make([]*wire.LabelKey, 0, len(infoKeys))
for _, key := range infoKeys {
labelKeys = append(labelKeys, &wire.LabelKey{
Key: fmt.Sprintf("%v", key.Name),
Key: key.Name(),
})
}

Просмотреть файл

@ -32,7 +32,7 @@ func TestEncodeMetric(t *testing.T) {
Info: &metric.Scalar{
Name: "int",
Description: "int metric",
Keys: []*event.Key{keyHello},
Keys: []event.Key{keyHello},
},
Rows: []int64{
1,
@ -91,7 +91,7 @@ func TestEncodeMetric(t *testing.T) {
Info: &metric.Scalar{
Name: "int-gauge",
Description: "int metric gauge",
Keys: []*event.Key{keyHello},
Keys: []event.Key{keyHello},
},
IsGauge: true,
})
@ -116,7 +116,7 @@ func TestEncodeMetric(t *testing.T) {
Info: &metric.Scalar{
Name: "float",
Description: "float metric",
Keys: []*event.Key{keyWorld},
Keys: []event.Key{keyWorld},
},
Rows: []float64{
1.5,
@ -165,7 +165,7 @@ func TestEncodeMetric(t *testing.T) {
Info: &metric.Scalar{
Name: "float-gauge",
Description: "float metric gauge",
Keys: []*event.Key{keyWorld},
Keys: []event.Key{keyWorld},
},
IsGauge: true,
})
@ -190,7 +190,7 @@ func TestEncodeMetric(t *testing.T) {
Info: &metric.HistogramInt64{
Name: "histogram int",
Description: "histogram int metric",
Keys: []*event.Key{keyHello},
Keys: []event.Key{keyHello},
Buckets: []int64{
0, 5, 10,
},
@ -263,7 +263,7 @@ func TestEncodeMetric(t *testing.T) {
Info: &metric.HistogramFloat64{
Name: "histogram float",
Description: "histogram float metric",
Keys: []*event.Key{keyHello},
Keys: []event.Key{keyHello},
Buckets: []float64{
0, 5,
},

Просмотреть файл

@ -233,7 +233,7 @@ func convertAttributes(tags event.TagList) *wire.Attributes {
}
attributes := make(map[string]wire.Attribute)
for _, tag := range tags {
attributes[tag.Key.Name] = convertAttribute(tag.Value)
attributes[tag.Key().Name()] = convertAttribute(tag.Value())
}
return &wire.Attributes{AttributeMap: attributes}
}

Просмотреть файл

@ -39,30 +39,30 @@ const testNodeStr = `{
},`
var (
keyDB = &event.Key{Name: "db"}
keyHello = &event.Key{Name: "hello"}
keyWorld = &event.Key{Name: "world"}
keyDB = event.NewStringKey("db", "the database name")
keyHello = event.NewStringKey("hello", "a metric grouping key")
keyWorld = event.NewStringKey("world", "another metric grouping key")
key1DB = &event.Key{Name: "1_db"}
key1DB = event.NewStringKey("1_db", "A test string key")
key2aAge = &event.Key{Name: "2a_age"}
key2bTTL = &event.Key{Name: "2b_ttl"}
key2cExpiryMS = &event.Key{Name: "2c_expiry_ms"}
key2aAge = event.NewFloat64Key("2a_age", "A test float64 key")
key2bTTL = event.NewFloat32Key("2b_ttl", "A test float32 key")
key2cExpiryMS = event.NewFloat64Key("2c_expiry_ms", "A test float64 key")
key3aRetry = &event.Key{Name: "3a_retry"}
key3bStale = &event.Key{Name: "3b_stale"}
key3aRetry = event.NewBooleanKey("3a_retry", "A test boolean key")
key3bStale = event.NewBooleanKey("3b_stale", "Another test boolean key")
key4aMax = &event.Key{Name: "4a_max"}
key4bOpcode = &event.Key{Name: "4b_opcode"}
key4cBase = &event.Key{Name: "4c_base"}
key4eChecksum = &event.Key{Name: "4e_checksum"}
key4fMode = &event.Key{Name: "4f_mode"}
key4aMax = event.NewIntKey("4a_max", "A test int key")
key4bOpcode = event.NewInt8Key("4b_opcode", "A test int8 key")
key4cBase = event.NewInt16Key("4c_base", "A test int16 key")
key4eChecksum = event.NewInt32Key("4e_checksum", "A test int32 key")
key4fMode = event.NewInt64Key("4f_mode", "A test int64 key")
key5aMin = &event.Key{Name: "5a_min"}
key5bMix = &event.Key{Name: "5b_mix"}
key5cPort = &event.Key{Name: "5c_port"}
key5dMinHops = &event.Key{Name: "5d_min_hops"}
key5eMaxHops = &event.Key{Name: "5e_max_hops"}
key5aMin = event.NewUIntKey("5a_min", "A test uint key")
key5bMix = event.NewUInt8Key("5b_mix", "A test uint8 key")
key5cPort = event.NewUInt16Key("5c_port", "A test uint16 key")
key5dMinHops = event.NewUInt32Key("5d_min_hops", "A test uint32 key")
key5eMaxHops = event.NewUInt64Key("5e_max_hops", "A test uint64 key")
)
type testExporter struct {

Просмотреть файл

@ -21,13 +21,14 @@ func Tag(ctx context.Context, ev event.Event) (context.Context, event.Event) {
switch {
case ev.IsLabel(), ev.IsStartSpan():
for _, t := range ev.Tags {
ctx = context.WithValue(ctx, t.Key, t.Value)
ctx = context.WithValue(ctx, t.Key(), t.Value())
}
default:
// all other types want the tags filled in if needed
for i := range ev.Tags {
if ev.Tags[i].Value == nil {
ev.Tags[i].Value = ctx.Value(ev.Tags[i].Key)
if ev.Tags[i].Value() == nil {
key := ev.Tags[i].Key()
ev.Tags[i] = key.OfValue(ctx.Value(key.Identity()))
}
}
}

Просмотреть файл

@ -21,7 +21,7 @@ type Scalar struct {
// Description can be used by observers to describe the metric to users.
Description string
// Keys is the set of tags that collectively describe rows of the metric.
Keys []*event.Key
Keys []event.Key
}
// HistogramInt64 represents the construction information for an int64 histogram metric.
@ -31,7 +31,7 @@ type HistogramInt64 struct {
// Description can be used by observers to describe the metric to users.
Description string
// Keys is the set of tags that collectively describe rows of the metric.
Keys []*event.Key
Keys []event.Key
// Buckets holds the inclusive upper bound of each bucket in the histogram.
Buckets []int64
}
@ -43,7 +43,7 @@ type HistogramFloat64 struct {
// Description can be used by observers to describe the metric to users.
Description string
// Keys is the set of tags that collectively describe rows of the metric.
Keys []*event.Key
Keys []event.Key
// Buckets holds the inclusive upper bound of each bucket in the histogram.
Buckets []float64
}
@ -201,7 +201,7 @@ type HistogramFloat64Row struct {
Max float64
}
func getGroup(ctx context.Context, g *[]event.TagList, keys []*event.Key) (int, bool) {
func getGroup(ctx context.Context, g *[]event.TagList, keys []event.Key) (int, bool) {
group := event.Query(ctx, keys...)
old := *g
index := sort.Search(len(old), func(i int) bool {