Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor zipkin/protov2.go #1747

Merged
merged 10 commits into from
Aug 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cmd/collector/app/zipkin/http_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,9 +295,9 @@ func TestSaveProtoSpansV2(t *testing.T) {
resBody string
}{
{Span: zipkinProto.Span{Id: validID, TraceId: validTraceID, LocalEndpoint: &zipkinProto.Endpoint{Ipv4: randBytesOfLen(4)}, Kind: zipkinProto.Span_CLIENT}, StatusCode: http.StatusAccepted},
{Span: zipkinProto.Span{Id: randBytesOfLen(4)}, StatusCode: http.StatusBadRequest, resBody: "Unable to process request body: invalid length for Span ID\n"},
{Span: zipkinProto.Span{Id: validID, TraceId: randBytesOfLen(32)}, StatusCode: http.StatusBadRequest, resBody: "Unable to process request body: invalid length for traceId\n"},
{Span: zipkinProto.Span{Id: validID, TraceId: validTraceID, ParentId: randBytesOfLen(16)}, StatusCode: http.StatusBadRequest, resBody: "Unable to process request body: invalid length for parentId\n"},
{Span: zipkinProto.Span{Id: randBytesOfLen(4)}, StatusCode: http.StatusBadRequest, resBody: "Unable to process request body: invalid length for SpanID\n"},
{Span: zipkinProto.Span{Id: validID, TraceId: randBytesOfLen(32)}, StatusCode: http.StatusBadRequest, resBody: "Unable to process request body: invalid length for TraceID\n"},
{Span: zipkinProto.Span{Id: validID, TraceId: validTraceID, ParentId: randBytesOfLen(16)}, StatusCode: http.StatusBadRequest, resBody: "Unable to process request body: invalid length for SpanID\n"},
{Span: zipkinProto.Span{Id: validID, TraceId: validTraceID, LocalEndpoint: &zipkinProto.Endpoint{Ipv4: randBytesOfLen(2)}}, StatusCode: http.StatusBadRequest, resBody: "Unable to process request body: wrong Ipv4\n"},
}
for _, test := range tests {
Expand Down
37 changes: 12 additions & 25 deletions cmd/collector/app/zipkin/protov2.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,17 @@ func protoSpansV2ToThrift(listOfSpans *zipkinProto.ListOfSpans) ([]*zipkincore.S
}

func protoSpanV2ToThrift(s *zipkinProto.Span) (*zipkincore.Span, error) {
if len(s.Id) != model.TraceIDShortBytesLen {
return nil, fmt.Errorf("invalid length for Span ID")
var id model.SpanID
var err error
if id, err = model.SpanIDFromBytes(s.Id); err != nil {
return nil, err
}
id := binary.BigEndian.Uint64(s.Id)
traceID, err := traceIDFromBytes(s.TraceId)
if err != nil {

var traceID model.TraceID
if traceID, err = model.TraceIDFromBytes(s.TraceId); err != nil {
return nil, err
}

ts, d := int64(s.Timestamp), int64(s.Duration)
tSpan := &zipkincore.Span{
ID: int64(id),
Expand All @@ -61,18 +64,17 @@ func protoSpanV2ToThrift(s *zipkinProto.Span) (*zipkincore.Span, error) {
}

if len(s.ParentId) > 0 {
if len(s.ParentId) != model.TraceIDShortBytesLen {
return nil, fmt.Errorf("invalid length for parentId")
var parentID model.SpanID
if parentID, err = model.SpanIDFromBytes(s.ParentId); err != nil {
return nil, err
}
parentID := binary.BigEndian.Uint64(s.ParentId)
signed := int64(parentID)
tSpan.ParentID = &signed
}

var localE *zipkincore.Endpoint
if s.LocalEndpoint != nil {
localE, err = protoEndpointV2ToThrift(s.LocalEndpoint)
if err != nil {
if localE, err = protoEndpointV2ToThrift(s.LocalEndpoint); err != nil {
return nil, err
}
}
Expand Down Expand Up @@ -105,21 +107,6 @@ func protoSpanV2ToThrift(s *zipkinProto.Span) (*zipkincore.Span, error) {
return tSpan, nil
}

func traceIDFromBytes(tid []byte) (model.TraceID, error) {
var hi, lo uint64
switch {
case len(tid) > model.TraceIDLongBytesLen:
return model.TraceID{}, fmt.Errorf("invalid length for traceId")
case len(tid) > model.TraceIDShortBytesLen:
hiLen := len(tid) - model.TraceIDShortBytesLen
hi = binary.BigEndian.Uint64(tid[:hiLen])
lo = binary.BigEndian.Uint64(tid[hiLen:])
default:
lo = binary.BigEndian.Uint64(tid)
}
return model.TraceID{High: hi, Low: lo}, nil
}

func protoRemoteEndpToAddrAnno(e *zipkinProto.Endpoint, kind zipkinProto.Span_Kind) (*zipkincore.BinaryAnnotation, error) {
rEndp, err := protoEndpointV2ToThrift(e)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions cmd/collector/app/zipkin/protov2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ func TestIdErrs(t *testing.T) {
span zipkinProto.Span
errMsg string
}{
{span: zipkinProto.Span{Id: randBytesOfLen(16)}, errMsg: "invalid length for Span ID"},
{span: zipkinProto.Span{Id: validID, TraceId: invalidTraceID}, errMsg: "invalid length for traceId"},
{span: zipkinProto.Span{Id: validID, TraceId: validTraceID, ParentId: invalidParentID}, errMsg: "invalid length for parentId"},
{span: zipkinProto.Span{Id: randBytesOfLen(16)}, errMsg: "invalid length for SpanID"},
{span: zipkinProto.Span{Id: validID, TraceId: invalidTraceID}, errMsg: "invalid length for TraceID"},
{span: zipkinProto.Span{Id: validID, TraceId: validTraceID, ParentId: invalidParentID}, errMsg: "invalid length for SpanID"},
}
for _, test := range tests {
_, err := protoSpanV2ToThrift(&test.span)
Expand Down
48 changes: 33 additions & 15 deletions model/ids.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ import (
)

const (
// TraceIDShortBytesLen indicates length of 64bit traceID when represented as list of bytes
TraceIDShortBytesLen = 8
// TraceIDLongBytesLen indicates length of 128bit traceID when represented as list of bytes
TraceIDLongBytesLen = 16
// traceIDShortBytesLen indicates length of 64bit traceID when represented as list of bytes
traceIDShortBytesLen = 8
// traceIDLongBytesLen indicates length of 128bit traceID when represented as list of bytes
traceIDLongBytesLen = 16
)

// TraceID is a random 128bit identifier for a trace
Expand Down Expand Up @@ -77,6 +77,21 @@ func TraceIDFromString(s string) (TraceID, error) {
return TraceID{High: hi, Low: lo}, nil
}

// TraceIDFromBytes creates a TraceID from list of bytes
func TraceIDFromBytes(data []byte) (TraceID, error) {
var t TraceID
switch {
case len(data) == traceIDLongBytesLen:
t.High = binary.BigEndian.Uint64(data[:traceIDShortBytesLen])
t.Low = binary.BigEndian.Uint64(data[traceIDShortBytesLen:])
case len(data) == traceIDShortBytesLen:
t.Low = binary.BigEndian.Uint64(data)
default:
return TraceID{}, fmt.Errorf("invalid length for TraceID")
}
return t, nil
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're adding a new function, I would prefer to reuse it from Unmarshal(data []byte), e.g.

func (t *TraceID) Unmarshal(data []byte) error {
    var err error
    *t, err = TraceIDFromBytes(data)
    return err
}

Similar for Unmarshal on SpanID

Copy link
Contributor Author

@jan25 jan25 Aug 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. And this change would let func (t *TraceID) Unmarshal parse 8byte long TraceID(Higher 8bytes will be 0)


// MarshalText is called by encoding/json, which we do not want people to use.
func (t TraceID) MarshalText() ([]byte, error) {
return nil, fmt.Errorf("unsupported method TraceID.MarshalText; please use github.com/gogo/protobuf/jsonpb for marshalling")
Expand All @@ -102,12 +117,9 @@ func (t *TraceID) MarshalTo(data []byte) (n int, err error) {

// Unmarshal inflates this trace ID from binary representation. Called by protobuf serialization.
func (t *TraceID) Unmarshal(data []byte) error {
if len(data) < 16 {
return fmt.Errorf("buffer is too short")
}
t.High = binary.BigEndian.Uint64(data[:8])
t.Low = binary.BigEndian.Uint64(data[8:])
return nil
var err error
*t, err = TraceIDFromBytes(data)
return err
}

func marshalBytes(dst []byte, src []byte) (n int, err error) {
Expand Down Expand Up @@ -166,6 +178,14 @@ func SpanIDFromString(s string) (SpanID, error) {
return SpanID(id), nil
}

// SpanIDFromBytes creates a SpandID from list of bytes
func SpanIDFromBytes(data []byte) (SpanID, error) {
jan25 marked this conversation as resolved.
Show resolved Hide resolved
if len(data) != traceIDShortBytesLen {
return SpanID(0), fmt.Errorf("invalid length for SpanID")
}
return NewSpanID(binary.BigEndian.Uint64(data)), nil
}

// MarshalText is called by encoding/json, which we do not want people to use.
func (s SpanID) MarshalText() ([]byte, error) {
return nil, fmt.Errorf("unsupported method SpanID.MarshalText; please use github.com/gogo/protobuf/jsonpb for marshalling")
Expand All @@ -190,11 +210,9 @@ func (s *SpanID) MarshalTo(data []byte) (n int, err error) {

// Unmarshal inflates span ID from a binary representation. Called by protobuf serialization.
func (s *SpanID) Unmarshal(data []byte) error {
if len(data) < 8 {
return fmt.Errorf("buffer is too short")
}
*s = NewSpanID(binary.BigEndian.Uint64(data))
return nil
var err error
*s, err = SpanIDFromBytes(data)
return err
}

// MarshalJSON converts span id into a base64 string enclosed in quotes.
Expand Down
42 changes: 42 additions & 0 deletions model/ids_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,45 @@ func TestTraceSpanIDMarshalProto(t *testing.T) {
})
}
}

func TestSpanIDFromBytes(t *testing.T) {
errTests := [][]byte{
{0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 13, 0},
}
for _, data := range errTests {
_, err := model.SpanIDFromBytes(data)
require.Error(t, err)
assert.Equal(t, err.Error(), "invalid length for SpanID")
}

spanID, err := model.SpanIDFromBytes([]byte{0, 0, 0, 0, 0, 0, 0, 13})
require.NoError(t, err)
assert.Equal(t, spanID, model.NewSpanID(13))
}

func TestTraceIDFromBytes(t *testing.T) {
errTests := [][]byte{
{0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 13},
{0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 13},
{0, 0, 0, 0, 0, 0, 13},
}
for _, data := range errTests {
_, err := model.TraceIDFromBytes(data)
require.Error(t, err)
assert.Equal(t, err.Error(), "invalid length for TraceID")
}

tests := []struct {
data []byte
expected model.TraceID
}{
{data: []byte{0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3}, expected: model.NewTraceID(2, 3)},
{data: []byte{0, 0, 0, 0, 0, 0, 0, 2}, expected: model.NewTraceID(0, 2)},
}
for _, test := range tests {
traceID, err := model.TraceIDFromBytes(test.data)
require.NoError(t, err)
assert.Equal(t, traceID, test.expected)
}
}
2 changes: 1 addition & 1 deletion model/span_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ func TestSpanIDUnmarshalJSONErrors(t *testing.T) {

err = id.UnmarshalJSONPB(nil, []byte(""))
require.Error(t, err)
assert.Contains(t, err.Error(), "buffer is too short")
assert.Contains(t, err.Error(), "invalid length for SpanID")
err = id.UnmarshalJSONPB(nil, []byte("123"))
require.Error(t, err)
assert.Contains(t, err.Error(), "illegal base64 data")
Expand Down