event: add Bytes value type and simplify the printer
Change-Id: Ia10aaf070ea545c70683d657aca010b754b63aed
Reviewed-on: https://go-review.googlesource.com/c/exp/+/324149
Trust: Ian Cottrell <iancottrell@google.com>
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/event/adapter/logfmt/logfmt.go b/event/adapter/logfmt/logfmt.go
index 40741cf..1a4a8ed 100644
--- a/event/adapter/logfmt/logfmt.go
+++ b/event/adapter/logfmt/logfmt.go
@@ -20,7 +20,8 @@
io.Writer
io.StringWriter
- buf [bufCap]byte
+ buf [bufCap]byte
+ needSep bool
}
type stringWriter struct {
@@ -41,67 +42,58 @@
func (p *Printer) Log(ctx context.Context, ev *event.Event) {
p.Event("log", ev)
- p.WriteString("\n")
}
func (p *Printer) Metric(ctx context.Context, ev *event.Event) {
p.Event("metric", ev)
- p.WriteString("\n")
}
func (p *Printer) Annotate(ctx context.Context, ev *event.Event) {
p.Event("annotate", ev)
- p.WriteString("\n")
}
func (p *Printer) Start(ctx context.Context, ev *event.Event) context.Context {
p.Event("start", ev)
- p.WriteString("\n")
return ctx
}
func (p *Printer) End(ctx context.Context, ev *event.Event) {
p.Event("end", ev)
- p.WriteString("\n")
}
func (p *Printer) Event(kind string, ev *event.Event) {
const timeFormat = "2006-01-02T15:04:05"
+ p.needSep = false
if !ev.At.IsZero() {
- p.WriteString("time=")
- p.Write(ev.At.AppendFormat(p.buf[:0], timeFormat))
- p.WriteString(" ")
+ p.label("time", event.BytesOf(ev.At.AppendFormat(p.buf[:0], timeFormat)))
}
- p.WriteString("id=")
- p.Write(strconv.AppendUint(p.buf[:0], ev.ID, 10))
+ p.label("id", event.BytesOf(strconv.AppendUint(p.buf[:0], ev.ID, 10)))
if ev.Parent != 0 {
- p.WriteString(" span=")
- p.Write(strconv.AppendUint(p.buf[:0], ev.Parent, 10))
+ p.label("span", event.BytesOf(strconv.AppendUint(p.buf[:0], ev.Parent, 10)))
}
- p.WriteString(" kind=")
- p.WriteString(kind)
+ p.label("kind", event.StringOf(kind))
for _, l := range ev.Labels {
if l.Name == "" {
continue
}
- p.WriteString(" ")
- p.Label(&l)
+ p.Label(l)
}
+ p.WriteString("\n")
}
-func (p *Printer) Label(l *event.Label) {
- p.Ident(l.Name)
- p.WriteString("=")
- p.Value(&l.Value)
+func (p *Printer) Label(l event.Label) {
+ p.label(l.Name, l.Value)
}
-func (p *Printer) Value(v *event.Value) {
+func (p *Printer) Value(v event.Value) {
switch {
case v.IsString():
p.Quote(v.String())
+ case v.IsBytes():
+ p.Bytes(v.Bytes())
case v.IsInt64():
p.Write(strconv.AppendInt(p.buf[:0], v.Int64(), 10))
case v.IsUint64():
@@ -151,6 +143,27 @@
p.WriteString(`"`)
}
+// Bytes writes a byte array in string form to the printer.
+func (p *Printer) Bytes(buf []byte) {
+ //TODO: non asci chars need escaping
+ p.Write(buf)
+}
+
+func (p *Printer) label(name string, value event.Value) {
+ if name == "" {
+ return
+ }
+ if p.needSep {
+ p.WriteString(" ")
+ }
+ p.needSep = true
+ p.Ident(name)
+ if value.HasValue() {
+ p.WriteString("=")
+ p.Value(value)
+ }
+}
+
func needQuote(s string) bool {
for _, r := range s {
if len(quoteRune(r)) > 0 {
diff --git a/event/label.go b/event/label.go
index 736b3f5..a867310 100644
--- a/event/label.go
+++ b/event/label.go
@@ -33,6 +33,9 @@
// stringptr is used in untyped when the Value is a string
type stringptr unsafe.Pointer
+// bytesptr is used in untyped when the Value is a byte slice
+type bytesptr unsafe.Pointer
+
// int64Kind is used in untyped when the Value is a signed integer
type int64Kind struct{}
@@ -133,12 +136,38 @@
}
}
-// IsString returns true if the value was built with SetString.
+// IsString returns true if the value was built with StringOf.
func (v Value) IsString() bool {
_, ok := v.untyped.(stringptr)
return ok
}
+// BytesOf returns a new Value for a string.
+func BytesOf(data []byte) Value {
+ hdr := (*reflect.SliceHeader)(unsafe.Pointer(&data))
+ return Value{packed: uint64(hdr.Len), untyped: bytesptr(hdr.Data)}
+}
+
+// Bytes returns the value as a bytes array.
+func (v Value) Bytes() []byte {
+ bp, ok := v.untyped.(bytesptr)
+ if !ok {
+ panic("Bytes called on non []byte value")
+ }
+ var buf []byte
+ hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
+ hdr.Data = uintptr(bp)
+ hdr.Len = int(v.packed)
+ hdr.Cap = hdr.Len // TODO: is this safe?
+ return buf
+}
+
+// IsBytes returns true if the value was built with BytesOf.
+func (v Value) IsBytes() bool {
+ _, ok := v.untyped.(bytesptr)
+ return ok
+}
+
// Int64Of returns a new Value for a signed integer.
func Int64Of(u int64) Value {
return Value{packed: uint64(u), untyped: int64Kind{}}