1
0

Update xorm to v1 (#323)

Fix limit for databases other than sqlite

go mod tidy && go mod vendor

Remove unneeded break statements

Make everything work with the new xorm version

Fix xorm logging

Fix lint

Fix redis init

Fix using id field

Fix database init for testing

Change default database log level

Add xorm logger

Use const for postgres

go mod tidy

Merge branch 'master' into update/xorm

# Conflicts:
#	go.mod
#	go.sum
#	vendor/modules.txt

go mod vendor

Fix loading fixtures for postgres

Go mod vendor1

Update xorm to version 1

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: https://kolaente.dev/vikunja/api/pulls/323
This commit is contained in:
konrad
2020-04-12 17:29:24 +00:00
parent 713560702b
commit d28f005552
430 changed files with 48291 additions and 99915 deletions

View File

@ -0,0 +1,113 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package event provides support for event based telemetry.
package event
import (
"fmt"
"time"
)
type eventType uint8
const (
invalidType = eventType(iota)
LogType // an event that should be recorded in a log
StartSpanType // the start of a span of time
EndSpanType // the end of a span of time
LabelType // some values that should be noted for later events
DetachType // an event that causes a context to detach
RecordType // a value that should be tracked
)
// sTags is used to hold a small number of tags inside an event whichout
// requiring a separate allocation.
// As tags are often on the stack, this avoids an allocation at all for
// the very common cases of simple events.
// The length needs to be large enough to cope with the majority of events
// but no so large as to cause undue stack pressure.
// A log message with two values will use 3 tags (one for each value and
// one for the message itself).
type sTags [3]Tag
// Event holds the information about an event of note that ocurred.
type Event struct {
At time.Time
typ eventType
static sTags // inline storage for the first few tags
dynamic []Tag // dynamically sized storage for remaining tags
}
// eventTagMap implements TagMap for a the tags of an Event.
type eventTagMap struct {
event Event
}
func (ev Event) IsLog() bool { return ev.typ == LogType }
func (ev Event) IsEndSpan() bool { return ev.typ == EndSpanType }
func (ev Event) IsStartSpan() bool { return ev.typ == StartSpanType }
func (ev Event) IsLabel() bool { return ev.typ == LabelType }
func (ev Event) IsDetach() bool { return ev.typ == DetachType }
func (ev Event) IsRecord() bool { return ev.typ == RecordType }
func (ev Event) Format(f fmt.State, r rune) {
tagMap := TagMap(ev)
if !ev.At.IsZero() {
fmt.Fprint(f, ev.At.Format("2006/01/02 15:04:05 "))
}
msg := Msg.Get(tagMap)
err := Err.Get(tagMap)
fmt.Fprint(f, msg)
if err != nil {
if f.Flag('+') {
fmt.Fprintf(f, ": %+v", err)
} else {
fmt.Fprintf(f, ": %v", err)
}
}
for index := 0; ev.Valid(index); index++ {
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 {
continue
}
fmt.Fprintf(f, "\n\t%v", tag)
}
}
func (ev Event) Valid(index int) bool {
return index >= 0 && index < len(ev.static)+len(ev.dynamic)
}
func (ev Event) Tag(index int) Tag {
if index < len(ev.static) {
return ev.static[index]
}
return ev.dynamic[index-len(ev.static)]
}
func (ev Event) Find(key interface{}) Tag {
for _, tag := range ev.static {
if tag.Key == key {
return tag
}
}
for _, tag := range ev.dynamic {
if tag.Key == key {
return tag
}
}
return Tag{}
}
func makeEvent(typ eventType, static sTags, tags []Tag) Event {
return Event{
typ: typ,
static: static,
dynamic: tags,
}
}

View File

@ -0,0 +1,68 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package event
import (
"context"
"sync/atomic"
"time"
"unsafe"
)
// Exporter is a function that handles events.
// It may return a modified context and event.
type Exporter func(context.Context, Event, TagMap) context.Context
var (
exporter unsafe.Pointer
)
// SetExporter sets the global exporter function that handles all events.
// The exporter is called synchronously from the event call site, so it should
// return quickly so as not to hold up user code.
func SetExporter(e Exporter) {
p := unsafe.Pointer(&e)
if e == nil {
// &e is always valid, and so p is always valid, but for the early abort
// of ProcessEvent to be efficient it needs to make the nil check on the
// pointer without having to dereference it, so we make the nil function
// also a nil pointer
p = nil
}
atomic.StorePointer(&exporter, p)
}
// deliver is called to deliver an event to the supplied exporter.
// it will fill in the time and generate the basic tag source.
func deliver(ctx context.Context, exporter Exporter, ev Event) context.Context {
// add the current time to the event
ev.At = time.Now()
// hand the event off to the current exporter
return exporter(ctx, ev, ev)
}
// dispatch is called to deliver an event to the global exporter if set.
func dispatch(ctx context.Context, ev Event) context.Context {
// get the global exporter and abort early if there is not one
exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter))
if exporterPtr == nil {
return ctx
}
return deliver(ctx, *exporterPtr, ev)
}
// dispatchPair is called to deliver a start event to the supplied exporter.
// It also returns a function that will deliver the end event to the same
// exporter.
// it will fill in the time and generate the basic tag source.
func dispatchPair(ctx context.Context, begin, end Event) (context.Context, func()) {
// get the global exporter and abort early if there is not one
exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter))
if exporterPtr == nil {
return ctx, func() {}
}
ctx = deliver(ctx, *exporterPtr, begin)
return ctx, func() { deliver(ctx, *exporterPtr, end) }
}

View File

@ -0,0 +1,499 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package event
import (
"math"
)
var (
// Msg is a key used to add message strings to tag lists.
Msg = NewStringKey("message", "a readable message")
// Name is used for things like traces that have a name.
Name = NewStringKey("name", "an entity name")
// Err is a key used to add error values to tag lists.
Err = NewErrorKey("error", "an error that occurred")
)
// Key is the interface shared by all key implementations.
type Key interface {
// Name returns the key name.
Name() string
// Description returns a string that can be used to describe the value.
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
description string
}
// NewKey creates a new Key for untyped values.
func NewKey(name, description string) *ValueKey {
return &ValueKey{name: name, description: description}
}
func (k *ValueKey) Name() string { return k.name }
func (k *ValueKey) Description() string { return k.description }
// Get can be used to get a tag for the key from a TagMap.
func (k *ValueKey) Get(tags TagMap) interface{} {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return nil
}
// From can be used to get a value from a Tag.
func (k *ValueKey) From(t Tag) interface{} { return t.untyped }
// 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} }
// IntKey represents a key
type IntKey struct {
name string
description string
}
// NewIntKey creates a new Key for int values.
func NewIntKey(name, description string) *IntKey {
return &IntKey{name: name, description: description}
}
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)} }
// Get can be used to get a tag for the key from a TagMap.
func (k *IntKey) Get(tags TagMap) int {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return 0
}
// From can be used to get a value from a Tag.
func (k *IntKey) From(t Tag) int { return int(t.packed) }
// Int8Key represents a key
type Int8Key struct {
name string
description string
}
// NewInt8Key creates a new Key for int8 values.
func NewInt8Key(name, description string) *Int8Key {
return &Int8Key{name: name, description: description}
}
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)} }
// Get can be used to get a tag for the key from a TagMap.
func (k *Int8Key) Get(tags TagMap) int8 {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return 0
}
// From can be used to get a value from a Tag.
func (k *Int8Key) From(t Tag) int8 { return int8(t.packed) }
// Int16Key represents a key
type Int16Key struct {
name string
description string
}
// NewInt16Key creates a new Key for int16 values.
func NewInt16Key(name, description string) *Int16Key {
return &Int16Key{name: name, description: description}
}
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)} }
// Get can be used to get a tag for the key from a TagMap.
func (k *Int16Key) Get(tags TagMap) int16 {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return 0
}
// From can be used to get a value from a Tag.
func (k *Int16Key) From(t Tag) int16 { return int16(t.packed) }
// Int32Key represents a key
type Int32Key struct {
name string
description string
}
// NewInt32Key creates a new Key for int32 values.
func NewInt32Key(name, description string) *Int32Key {
return &Int32Key{name: name, description: description}
}
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)} }
// Get can be used to get a tag for the key from a TagMap.
func (k *Int32Key) Get(tags TagMap) int32 {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return 0
}
// From can be used to get a value from a Tag.
func (k *Int32Key) From(t Tag) int32 { return int32(t.packed) }
// Int64Key represents a key
type Int64Key struct {
name string
description string
}
// NewInt64Key creates a new Key for int64 values.
func NewInt64Key(name, description string) *Int64Key {
return &Int64Key{name: name, description: description}
}
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)} }
// Get can be used to get a tag for the key from a TagMap.
func (k *Int64Key) Get(tags TagMap) int64 {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return 0
}
// From can be used to get a value from a Tag.
func (k *Int64Key) From(t Tag) int64 { return int64(t.packed) }
// UIntKey represents a key
type UIntKey struct {
name string
description string
}
// NewUIntKey creates a new Key for uint values.
func NewUIntKey(name, description string) *UIntKey {
return &UIntKey{name: name, description: description}
}
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)} }
// Get can be used to get a tag for the key from a TagMap.
func (k *UIntKey) Get(tags TagMap) uint {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return 0
}
// From can be used to get a value from a Tag.
func (k *UIntKey) From(t Tag) uint { return uint(t.packed) }
// UInt8Key represents a key
type UInt8Key struct {
name string
description string
}
// NewUInt8Key creates a new Key for uint8 values.
func NewUInt8Key(name, description string) *UInt8Key {
return &UInt8Key{name: name, description: description}
}
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)} }
// Get can be used to get a tag for the key from a TagMap.
func (k *UInt8Key) Get(tags TagMap) uint8 {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return 0
}
// From can be used to get a value from a Tag.
func (k *UInt8Key) From(t Tag) uint8 { return uint8(t.packed) }
// UInt16Key represents a key
type UInt16Key struct {
name string
description string
}
// NewUInt16Key creates a new Key for uint16 values.
func NewUInt16Key(name, description string) *UInt16Key {
return &UInt16Key{name: name, description: description}
}
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)} }
// Get can be used to get a tag for the key from a TagMap.
func (k *UInt16Key) Get(tags TagMap) uint16 {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return 0
}
// From can be used to get a value from a Tag.
func (k *UInt16Key) From(t Tag) uint16 { return uint16(t.packed) }
// UInt32Key represents a key
type UInt32Key struct {
name string
description string
}
// NewUInt32Key creates a new Key for uint32 values.
func NewUInt32Key(name, description string) *UInt32Key {
return &UInt32Key{name: name, description: description}
}
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)} }
// Get can be used to get a tag for the key from a TagMap.
func (k *UInt32Key) Get(tags TagMap) uint32 {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return 0
}
// From can be used to get a value from a Tag.
func (k *UInt32Key) From(t Tag) uint32 { return uint32(t.packed) }
// UInt64Key represents a key
type UInt64Key struct {
name string
description string
}
// NewUInt64Key creates a new Key for uint64 values.
func NewUInt64Key(name, description string) *UInt64Key {
return &UInt64Key{name: name, description: description}
}
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} }
// Get can be used to get a tag for the key from a TagMap.
func (k *UInt64Key) Get(tags TagMap) uint64 {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return 0
}
// From can be used to get a value from a Tag.
func (k *UInt64Key) From(t Tag) uint64 { return t.packed }
// Float32Key represents a key
type Float32Key struct {
name string
description string
}
// NewFloat32Key creates a new Key for float32 values.
func NewFloat32Key(name, description string) *Float32Key {
return &Float32Key{name: name, description: description}
}
func (k *Float32Key) Name() string { return k.name }
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))}
}
// Get can be used to get a tag for the key from a TagMap.
func (k *Float32Key) Get(tags TagMap) float32 {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return 0
}
// From can be used to get a value from a Tag.
func (k *Float32Key) From(t Tag) float32 {
return math.Float32frombits(uint32(t.packed))
}
// Float64Key represents a key
type Float64Key struct {
name string
description string
}
// NewFloat64Key creates a new Key for int64 values.
func NewFloat64Key(name, description string) *Float64Key {
return &Float64Key{name: name, description: description}
}
func (k *Float64Key) Name() string { return k.name }
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)}
}
// Get can be used to get a tag for the key from a TagMap.
func (k *Float64Key) Get(tags TagMap) float64 {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return 0
}
// From can be used to get a value from a Tag.
func (k *Float64Key) From(t Tag) float64 {
return math.Float64frombits(t.packed)
}
// StringKey represents a key
type StringKey struct {
name string
description string
}
// NewStringKey creates a new Key for int64 values.
func NewStringKey(name, description string) *StringKey {
return &StringKey{name: name, description: description}
}
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} }
// Get can be used to get a tag for the key from a TagMap.
func (k *StringKey) Get(tags TagMap) string {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return ""
}
// From can be used to get a value from a Tag.
func (k *StringKey) From(t Tag) string { return t.str }
// BooleanKey represents a key
type BooleanKey struct {
name string
description string
}
// NewBooleanKey creates a new Key for bool values.
func NewBooleanKey(name, description string) *BooleanKey {
return &BooleanKey{name: name, description: description}
}
func (k *BooleanKey) Name() string { return k.name }
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 t
}
// Get can be used to get a tag for the key from a TagMap.
func (k *BooleanKey) Get(tags TagMap) bool {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return false
}
// From can be used to get a value from a Tag.
func (k *BooleanKey) From(t Tag) bool { return t.packed > 0 }
// ErrorKey represents a key
type ErrorKey struct {
name string
description string
}
// NewErrorKey creates a new Key for int64 values.
func NewErrorKey(name, description string) *ErrorKey {
return &ErrorKey{name: name, description: description}
}
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} }
// Get can be used to get a tag for the key from a TagMap.
func (k *ErrorKey) Get(tags TagMap) error {
if t := tags.Find(k); t.Valid() {
return k.From(t)
}
return nil
}
// From can be used to get a value from a Tag.
func (k *ErrorKey) From(t Tag) error {
err, _ := t.untyped.(error)
return err
}

View File

@ -0,0 +1,29 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package event
import (
"context"
)
// Label sends a label event to the exporter with the supplied tags.
func Label(ctx context.Context, tags ...Tag) context.Context {
return dispatch(ctx, makeEvent(LabelType, sTags{}, tags))
}
// Label1 sends a label event to the exporter with the supplied tags.
func Label1(ctx context.Context, t1 Tag) context.Context {
return dispatch(ctx, makeEvent(LabelType, sTags{t1}, nil))
}
// Label2 sends a label event to the exporter with the supplied tags.
func Label2(ctx context.Context, t1, t2 Tag) context.Context {
return dispatch(ctx, makeEvent(LabelType, sTags{t1, t2}, nil))
}
// Label3 sends a label event to the exporter with the supplied tags.
func Label3(ctx context.Context, t1, t2, t3 Tag) context.Context {
return dispatch(ctx, makeEvent(LabelType, sTags{t1, t2, t3}, nil))
}

View File

@ -0,0 +1,59 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package event
import (
"context"
"errors"
)
// Log sends a log event with the supplied tag list to the exporter.
func Log(ctx context.Context, tags ...Tag) {
dispatch(ctx, makeEvent(LogType, sTags{}, tags))
}
// Log1 sends a label event to the exporter with the supplied tags.
func Log1(ctx context.Context, t1 Tag) context.Context {
return dispatch(ctx, makeEvent(LogType, sTags{t1}, nil))
}
// Log2 sends a label event to the exporter with the supplied tags.
func Log2(ctx context.Context, t1, t2 Tag) context.Context {
return dispatch(ctx, makeEvent(LogType, sTags{t1, t2}, nil))
}
// Log3 sends a label event to the exporter with the supplied tags.
func Log3(ctx context.Context, t1, t2, t3 Tag) context.Context {
return dispatch(ctx, makeEvent(LogType, sTags{t1, t2, t3}, nil))
}
// Print takes a message and a tag list and combines them into a single event
// before delivering them to the exporter.
func Print(ctx context.Context, message string, tags ...Tag) {
dispatch(ctx, makeEvent(LogType, sTags{Msg.Of(message)}, tags))
}
// Print1 takes a message and one tag delivers a log event to the exporter.
// It is a customized version of Print that is faster and does no allocation.
func Print1(ctx context.Context, message string, t1 Tag) {
dispatch(ctx, makeEvent(LogType, sTags{Msg.Of(message), t1}, nil))
}
// Print2 takes a message and two tags and delivers a log event to the exporter.
// It is a customized version of Print that is faster and does no allocation.
func Print2(ctx context.Context, message string, t1 Tag, t2 Tag) {
dispatch(ctx, makeEvent(LogType, sTags{Msg.Of(message), t1, t2}, nil))
}
// Error takes a message and a tag list and combines them into a single event
// before delivering them to the exporter. It captures the error in the
// delivered event.
func Error(ctx context.Context, message string, err error, tags ...Tag) {
if err == nil {
err = errors.New(message)
message = ""
}
dispatch(ctx, makeEvent(LogType, sTags{Msg.Of(message), Err.Of(err)}, tags))
}

View File

@ -0,0 +1,29 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package event
import (
"context"
)
// Record sends a label event to the exporter with the supplied tags.
func Record(ctx context.Context, tags ...Tag) context.Context {
return dispatch(ctx, makeEvent(RecordType, sTags{}, tags))
}
// Record1 sends a label event to the exporter with the supplied tags.
func Record1(ctx context.Context, t1 Tag) context.Context {
return dispatch(ctx, makeEvent(RecordType, sTags{t1}, nil))
}
// Record2 sends a label event to the exporter with the supplied tags.
func Record2(ctx context.Context, t1, t2 Tag) context.Context {
return dispatch(ctx, makeEvent(RecordType, sTags{t1, t2}, nil))
}
// Record3 sends a label event to the exporter with the supplied tags.
func Record3(ctx context.Context, t1, t2, t3 Tag) context.Context {
return dispatch(ctx, makeEvent(RecordType, sTags{t1, t2, t3}, nil))
}

View File

@ -0,0 +1,168 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package event
import (
"fmt"
)
// Tag holds a key and value pair.
// It is normally used when passing around lists of tags.
type Tag struct {
Key Key
packed uint64
str string
untyped interface{}
}
// 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
}
// TagList is the interface to something that provides an iterable
// list of tags.
// Iteration should start from 0 and continue until Valid returns false.
type TagList interface {
// Valid returns true if the index is within range for the list.
// It does not imply the tag at that index will itself be valid.
Valid(index int) bool
// Tag returns the tag at the given index.
Tag(index int) Tag
}
// tagList implements TagList for a list of Tags.
type tagList struct {
tags []Tag
}
// tagFilter wraps a TagList filtering out specific tags.
type tagFilter struct {
keys []Key
underlying TagList
}
// tagMap implements TagMap for a simple list of tags.
type tagMap struct {
tags []Tag
}
// tagMapChain implements TagMap for a list of underlying TagMap.
type tagMapChain struct {
maps []TagMap
}
// Valid returns true if the Tag is a valid one (it has a key).
func (t Tag) Valid() bool { return t.Key != nil }
// Format is used for debug printing of tags.
func (t Tag) Format(f fmt.State, r rune) {
if !t.Valid() {
fmt.Fprintf(f, `nil`)
return
}
switch key := t.Key.(type) {
case *IntKey:
fmt.Fprintf(f, "%s=%d", key.Name(), key.From(t))
case *Int8Key:
fmt.Fprintf(f, "%s=%d", key.Name(), key.From(t))
case *Int16Key:
fmt.Fprintf(f, "%s=%d", key.Name(), key.From(t))
case *Int32Key:
fmt.Fprintf(f, "%s=%d", key.Name(), key.From(t))
case *Int64Key:
fmt.Fprintf(f, "%s=%d", key.Name(), key.From(t))
case *UIntKey:
fmt.Fprintf(f, "%s=%d", key.Name(), key.From(t))
case *UInt8Key:
fmt.Fprintf(f, "%s=%d", key.Name(), key.From(t))
case *UInt16Key:
fmt.Fprintf(f, "%s=%d", key.Name(), key.From(t))
case *UInt32Key:
fmt.Fprintf(f, "%s=%d", key.Name(), key.From(t))
case *UInt64Key:
fmt.Fprintf(f, "%s=%d", key.Name(), key.From(t))
case *Float32Key:
fmt.Fprintf(f, "%s=%g", key.Name(), key.From(t))
case *Float64Key:
fmt.Fprintf(f, "%s=%g", key.Name(), key.From(t))
case *BooleanKey:
fmt.Fprintf(f, "%s=%t", key.Name(), key.From(t))
case *StringKey:
fmt.Fprintf(f, "%s=%q", key.Name(), key.From(t))
case *ErrorKey:
fmt.Fprintf(f, "%s=%v", key.Name(), key.From(t))
case *ValueKey:
fmt.Fprintf(f, "%s=%v", key.Name(), key.From(t))
default:
fmt.Fprintf(f, `%s="invalid type %T"`, key.Name(), key)
}
}
func (l *tagList) Valid(index int) bool {
return index >= 0 && index < len(l.tags)
}
func (l *tagList) Tag(index int) Tag {
return l.tags[index]
}
func (f *tagFilter) Valid(index int) bool {
return f.underlying.Valid(index)
}
func (f *tagFilter) Tag(index int) Tag {
tag := f.underlying.Tag(index)
for _, f := range f.keys {
if tag.Key == f {
return Tag{}
}
}
return tag
}
func (l tagMap) Find(key interface{}) Tag {
for _, tag := range l.tags {
if tag.Key == key {
return tag
}
}
return Tag{}
}
func (c tagMapChain) Find(key interface{}) Tag {
for _, src := range c.maps {
tag := src.Find(key)
if tag.Valid() {
return tag
}
}
return Tag{}
}
var emptyList = &tagList{}
func NewTagList(tags ...Tag) TagList {
if len(tags) == 0 {
return emptyList
}
return &tagList{tags: tags}
}
func Filter(l TagList, keys ...Key) TagList {
if len(keys) == 0 {
return l
}
return &tagFilter{keys: keys, underlying: l}
}
func NewTagMap(tags ...Tag) TagMap {
return tagMap{tags: tags}
}
func MergeTagMaps(srcs ...TagMap) TagMap {
return tagMapChain{maps: srcs}
}

View File

@ -0,0 +1,42 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package event
import (
"context"
)
// StartSpan sends a span start event with the supplied tag list to the exporter.
// It also returns a function that will end the span, which should normally be
// deferred.
func StartSpan(ctx context.Context, name string, tags ...Tag) (context.Context, func()) {
return dispatchPair(ctx,
makeEvent(StartSpanType, sTags{Name.Of(name)}, tags),
makeEvent(EndSpanType, sTags{}, nil))
}
// StartSpan1 sends a span start event with the supplied tag list to the exporter.
// It also returns a function that will end the span, which should normally be
// deferred.
func StartSpan1(ctx context.Context, name string, t1 Tag) (context.Context, func()) {
return dispatchPair(ctx,
makeEvent(StartSpanType, sTags{Name.Of(name), t1}, nil),
makeEvent(EndSpanType, sTags{}, nil))
}
// StartSpan2 sends a span start event with the supplied tag list to the exporter.
// It also returns a function that will end the span, which should normally be
// deferred.
func StartSpan2(ctx context.Context, name string, t1, t2 Tag) (context.Context, func()) {
return dispatchPair(ctx,
makeEvent(StartSpanType, sTags{Name.Of(name), t1, t2}, nil),
makeEvent(EndSpanType, sTags{}, nil))
}
// Detach returns a context without an associated span.
// This allows the creation of spans that are not children of the current span.
func Detach(ctx context.Context) context.Context {
return dispatch(ctx, makeEvent(DetachType, sTags{}, nil))
}