diff --git a/qlog/event.go b/qlog/event.go new file mode 100644 index 00000000..9d49f87d --- /dev/null +++ b/qlog/event.go @@ -0,0 +1,41 @@ +package qlog + +import ( + "time" + + "github.com/francoispqt/gojay" +) + +var eventFields = [4]string{"time", "category", "event", "data"} + +type events []event + +var _ gojay.MarshalerJSONArray = events{} + +func (e events) IsNil() bool { return e == nil } +func (e events) MarshalJSONArray(enc *gojay.Encoder) { + for _, ev := range e { + enc.Array(ev) + } +} + +type eventDetails interface { + Category() category + Name() string + gojay.MarshalerJSONObject +} + +type event struct { + Time time.Time + eventDetails +} + +var _ gojay.MarshalerJSONArray = event{} + +func (e event) IsNil() bool { return false } +func (e event) MarshalJSONArray(enc *gojay.Encoder) { + enc.Float64(float64(e.Time.UnixNano()) / 1e6) + enc.String(e.Category().String()) + enc.String(e.Name()) + enc.Object(e.eventDetails) +} diff --git a/qlog/event_test.go b/qlog/event_test.go new file mode 100644 index 00000000..5112f213 --- /dev/null +++ b/qlog/event_test.go @@ -0,0 +1,54 @@ +package qlog + +import ( + "bytes" + "encoding/json" + "time" + + "github.com/francoispqt/gojay" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type mevent struct{} + +var _ eventDetails = mevent{} + +func (mevent) Category() category { return categoryConnectivity } +func (mevent) Name() string { return "mevent" } +func (mevent) IsNil() bool { return false } +func (mevent) MarshalJSONObject(enc *gojay.Encoder) { enc.StringKey("event", "details") } + +var _ = Describe("Events", func() { + It("marshals the fields before the event details", func() { + now := time.Now() + + buf := &bytes.Buffer{} + enc := gojay.NewEncoder(buf) + Expect(enc.Encode(event{ + Time: now, + eventDetails: mevent{}, + })).To(Succeed()) + + var decoded []interface{} + Expect(json.Unmarshal(buf.Bytes(), &decoded)).To(Succeed()) + Expect(decoded).To(HaveLen(4)) + + // 1st field + Expect(eventFields[0]).To(Equal("time")) + Expect(time.Unix(0, int64(1e6*decoded[0].(float64)))).To(BeTemporally("~", now, 2*time.Microsecond)) + + // 2nd field + Expect(eventFields[1]).To(Equal("category")) + Expect(decoded[1].(string)).To(Equal(categoryConnectivity.String())) + + // 3rd field + Expect(eventFields[2]).To(Equal("event")) + Expect(decoded[2].(string)).To(Equal("mevent")) + + // 4th field + Expect(eventFields[3]).To(Equal("data")) + Expect(decoded[3].(map[string]interface{})["event"]).To(Equal("details")) + }) +}) diff --git a/qlog/types.go b/qlog/types.go index 02154ad7..de24581c 100644 --- a/qlog/types.go +++ b/qlog/types.go @@ -35,3 +35,28 @@ type connectionID protocol.ConnectionID func (c connectionID) String() string { return fmt.Sprintf("%x", []byte(c)) } + +// category is the qlog event category. +type category uint8 + +const ( + categoryConnectivity category = iota + categoryTransport + categorySecurity + categoryRecovery +) + +func (c category) String() string { + switch c { + case categoryConnectivity: + return "connectivity" + case categoryTransport: + return "transport" + case categorySecurity: + return "security" + case categoryRecovery: + return "recovery" + default: + panic("unknown category") + } +} diff --git a/qlog/types_test.go b/qlog/types_test.go new file mode 100644 index 00000000..c2f2e68b --- /dev/null +++ b/qlog/types_test.go @@ -0,0 +1,15 @@ +package qlog + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Types", func() { + It("has a string representation for the category", func() { + Expect(categoryConnectivity.String()).To(Equal("connectivity")) + Expect(categoryTransport.String()).To(Equal("transport")) + Expect(categoryRecovery.String()).To(Equal("recovery")) + Expect(categorySecurity.String()).To(Equal("security")) + }) +})