forked from quic-go/quic-go
implement marshalling of the trace
This commit is contained in:
50
qlog/qlog.go
Normal file
50
qlog/qlog.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package qlog
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/francoispqt/gojay"
|
||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||
)
|
||||
|
||||
// A Tracer records events to be exported to a qlog.
|
||||
type Tracer interface {
|
||||
Export() error
|
||||
}
|
||||
|
||||
type tracer struct {
|
||||
w io.WriteCloser
|
||||
odcid protocol.ConnectionID
|
||||
perspective protocol.Perspective
|
||||
|
||||
events []event
|
||||
}
|
||||
|
||||
var _ Tracer = &tracer{}
|
||||
|
||||
// NewTracer creates a new tracer to record a qlog.
|
||||
func NewTracer(w io.WriteCloser, p protocol.Perspective, odcid protocol.ConnectionID) Tracer {
|
||||
return &tracer{
|
||||
w: w,
|
||||
perspective: p,
|
||||
odcid: odcid,
|
||||
}
|
||||
}
|
||||
|
||||
// Export writes a qlog.
|
||||
func (t *tracer) Export() error {
|
||||
enc := gojay.NewEncoder(t.w)
|
||||
tl := &topLevel{
|
||||
traces: traces{
|
||||
{
|
||||
VantagePoint: vantagePoint{Type: t.perspective},
|
||||
CommonFields: commonFields{ODCID: connectionID(t.odcid), GroupID: connectionID(t.odcid)},
|
||||
EventFields: eventFields[:],
|
||||
Events: t.events,
|
||||
},
|
||||
}}
|
||||
if err := enc.Encode(tl); err != nil {
|
||||
return err
|
||||
}
|
||||
return t.w.Close()
|
||||
}
|
||||
60
qlog/qlog_test.go
Normal file
60
qlog/qlog_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package qlog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
type nopWriteCloserImpl struct{ io.Writer }
|
||||
|
||||
func (nopWriteCloserImpl) Close() error { return nil }
|
||||
|
||||
func nopWriteCloser(w io.Writer) io.WriteCloser {
|
||||
return &nopWriteCloserImpl{Writer: w}
|
||||
}
|
||||
|
||||
var _ = Describe("Tracer", func() {
|
||||
var (
|
||||
tracer Tracer
|
||||
buf *bytes.Buffer
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
buf = &bytes.Buffer{}
|
||||
tracer = NewTracer(
|
||||
nopWriteCloser(buf),
|
||||
protocol.PerspectiveServer,
|
||||
protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef},
|
||||
)
|
||||
})
|
||||
|
||||
It("exports a trace that has the right metadata", func() {
|
||||
Expect(tracer.Export()).To(Succeed())
|
||||
|
||||
m := make(map[string]interface{})
|
||||
Expect(json.Unmarshal(buf.Bytes(), &m)).To(Succeed())
|
||||
Expect(m).To(HaveKeyWithValue("qlog_version", "draft-02-wip"))
|
||||
Expect(m).To(HaveKey("title"))
|
||||
Expect(m).To(HaveKey("traces"))
|
||||
traces := m["traces"].([]interface{})
|
||||
Expect(traces).To(HaveLen(1))
|
||||
trace := traces[0].(map[string]interface{})
|
||||
Expect(trace).To(HaveKey(("common_fields")))
|
||||
commonFields := trace["common_fields"].(map[string]interface{})
|
||||
Expect(commonFields).To(HaveKeyWithValue("ODCID", "deadbeef"))
|
||||
Expect(commonFields).To(HaveKeyWithValue("group_id", "deadbeef"))
|
||||
Expect(trace).To(HaveKey("event_fields"))
|
||||
for i, ef := range trace["event_fields"].([]interface{}) {
|
||||
Expect(ef.(string)).To(Equal(eventFields[i]))
|
||||
}
|
||||
Expect(trace).To(HaveKey("vantage_point"))
|
||||
vantagePoint := trace["vantage_point"].(map[string]interface{})
|
||||
Expect(vantagePoint).To(HaveKeyWithValue("type", "server"))
|
||||
})
|
||||
})
|
||||
72
qlog/trace.go
Normal file
72
qlog/trace.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package qlog
|
||||
|
||||
import (
|
||||
"github.com/francoispqt/gojay"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||
)
|
||||
|
||||
type topLevel struct {
|
||||
traces traces
|
||||
}
|
||||
|
||||
func (topLevel) IsNil() bool { return false }
|
||||
func (l topLevel) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("qlog_version", "draft-02-wip")
|
||||
enc.StringKeyOmitEmpty("title", "quic-go qlog")
|
||||
enc.ArrayKey("traces", l.traces)
|
||||
}
|
||||
|
||||
type vantagePoint struct {
|
||||
Name string
|
||||
Type protocol.Perspective
|
||||
}
|
||||
|
||||
func (p vantagePoint) IsNil() bool { return false }
|
||||
func (p vantagePoint) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKeyOmitEmpty("name", p.Name)
|
||||
switch p.Type {
|
||||
case protocol.PerspectiveClient:
|
||||
enc.StringKey("type", "client")
|
||||
case protocol.PerspectiveServer:
|
||||
enc.StringKey("type", "server")
|
||||
}
|
||||
}
|
||||
|
||||
type commonFields struct {
|
||||
ODCID connectionID
|
||||
GroupID connectionID
|
||||
ProtocolType string
|
||||
}
|
||||
|
||||
func (f commonFields) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("ODCID", f.ODCID.String())
|
||||
enc.StringKey("group_id", f.ODCID.String())
|
||||
enc.StringKeyOmitEmpty("protocol_type", f.ProtocolType)
|
||||
}
|
||||
|
||||
func (f commonFields) IsNil() bool { return false }
|
||||
|
||||
type traces []trace
|
||||
|
||||
func (t traces) IsNil() bool { return t == nil }
|
||||
func (t traces) MarshalJSONArray(enc *gojay.Encoder) {
|
||||
for _, tr := range t {
|
||||
enc.Object(tr)
|
||||
}
|
||||
}
|
||||
|
||||
type trace struct {
|
||||
VantagePoint vantagePoint
|
||||
CommonFields commonFields
|
||||
EventFields []string
|
||||
Events events
|
||||
}
|
||||
|
||||
func (trace) IsNil() bool { return false }
|
||||
func (t trace) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.ObjectKey("vantage_point", t.VantagePoint)
|
||||
enc.ObjectKey("common_fields", t.CommonFields)
|
||||
enc.SliceStringKey("event_fields", t.EventFields)
|
||||
enc.ArrayKey("events", t.Events)
|
||||
}
|
||||
Reference in New Issue
Block a user