// 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 := ev.Map() 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 it := ev.Tags(); it.Valid(); it.Advance() { tag := it.Tag() fmt.Fprintf(f, "\n\t%v", tag) } } func (ev Event) Tags() TagIterator { return ChainTagIterators( NewTagIterator(ev.static[:]...), NewTagIterator(ev.dynamic...)) } func (ev Event) Map() TagMap { return &eventTagMap{event: ev} } func (m *eventTagMap) Find(key interface{}) Tag { for _, tag := range m.event.static { if tag.Key == key { return tag } } for _, tag := range m.event.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, } }