Skip to content
This repository has been archived by the owner on Mar 6, 2023. It is now read-only.

Commit

Permalink
Add protocol buffers for binary injection/joining
Browse files Browse the repository at this point in the history
Replace the internal use of `encoding/binary` inside of
`(*binaryPropagator).Join` and `(*binaryPropagator).Inject`
with Google's Protocol buffers. Gogoproto is used for the go code
generation since it provides considerable performance gains over the
protobuf.

```
name                                             old time/op    new time/op    delta
Span_Empty-2                                        742ns ± 0%     743ns ± 0%   +0.19%         (p=0.000 n=9+10)
Span_100Events-2                                   50.2µs ± 1%    50.2µs ± 1%     ~           (p=0.853 n=10+10)
Span_1000Events-2                                  50.1µs ± 0%    50.2µs ± 1%     ~            (p=0.182 n=9+10)
Span_100Tags-2                                     46.8µs ± 1%    47.0µs ± 0%   +0.36%         (p=0.043 n=9+10)
Span_1000Tags-2                                    46.8µs ± 1%    47.0µs ± 1%   +0.48%         (p=0.004 n=10+9)
Span_100BaggageItems-2                              154µs ± 0%     155µs ± 1%   +0.28%         (p=0.013 n=9+10)
TrimmedSpan_100Events_100Tags_100BaggageItems-2     178µs ± 0%     179µs ± 0%   +0.30%        (p=0.000 n=10+10)
Inject_TextMap_Empty-2                             2.49µs ± 2%    2.47µs ± 1%     ~            (p=0.095 n=10+8)
Inject_TextMap_100BaggageItems-2                    101µs ± 1%     102µs ± 1%   +0.90%        (p=0.011 n=10+10)
Inject_Binary_Empty-2                              1.03µs ± 0%    0.49µs ± 0%  -51.95%         (p=0.000 n=10+7)
Inject_Binary_100BaggageItems-2                    61.0µs ± 1%    16.0µs ± 2%  -73.85%         (p=0.000 n=10+9)
Join_TextMap_Empty-2                               3.34µs ± 0%    3.48µs ± 0%   +4.23%        (p=0.000 n=10+10)
Join_TextMap_100BaggageItems-2                      155µs ± 0%     157µs ± 0%   +1.17%         (p=0.000 n=10+9)
Join_Binary_Empty-2                                1.75µs ± 1%    1.49µs ± 0%  -15.14%        (p=0.000 n=10+10)
Join_Binary_100BaggageItems-2                      95.4µs ± 0%    46.6µs ± 1%  -51.18%        (p=0.000 n=10+10)

name                                             old alloc/op   new alloc/op   delta
Span_Empty-2                                       0.00B ±NaN%    0.00B ±NaN%     ~     (all samples are equal)
Span_100Events-2                                   16.1kB ± 0%    16.1kB ± 0%     ~     (all samples are equal)
Span_1000Events-2                                  16.1kB ± 0%    16.1kB ± 0%     ~     (all samples are equal)
Span_100Tags-2                                     10.5kB ± 0%    10.5kB ± 0%     ~           (p=1.000 n=10+10)
Span_1000Tags-2                                    10.5kB ± 0%    10.5kB ± 0%     ~            (p=0.946 n=9+10)
Span_100BaggageItems-2                             10.5kB ± 0%    10.5kB ± 0%     ~           (p=0.590 n=10+10)
TrimmedSpan_100Events_100Tags_100BaggageItems-2    0.00B ±NaN%    0.00B ±NaN%     ~     (all samples are equal)
Inject_TextMap_Empty-2                               393B ± 0%      393B ± 0%     ~     (all samples are equal)
Inject_TextMap_100BaggageItems-2                   15.0kB ± 0%    15.0kB ± 0%     ~     (all samples are equal)
Inject_Binary_Empty-2                                219B ± 0%      168B ± 0%  -23.29%        (p=0.000 n=10+10)
Inject_Binary_100BaggageItems-2                    23.8kB ± 1%    16.3kB ± 0%  -31.34%        (p=0.000 n=10+10)
Join_TextMap_Empty-2                                 368B ± 0%      368B ± 0%     ~     (all samples are equal)
Join_TextMap_100BaggageItems-2                     23.6kB ± 0%    23.6kB ± 0%     ~           (p=0.970 n=10+10)
Join_Binary_Empty-2                                  256B ± 0%      224B ± 0%  -12.50%        (p=0.000 n=10+10)
Join_Binary_100BaggageItems-2                      22.5kB ± 0%    21.7kB ± 0%   -3.49%         (p=0.000 n=10+9)

name                                             old allocs/op  new allocs/op  delta
Span_Empty-2                                        0.00 ±NaN%     0.00 ±NaN%     ~     (all samples are equal)
Span_100Events-2                                     8.00 ± 0%      8.00 ± 0%     ~     (all samples are equal)
Span_1000Events-2                                    8.00 ± 0%      8.00 ± 0%     ~     (all samples are equal)
Span_100Tags-2                                       11.0 ± 0%      11.0 ± 0%     ~     (all samples are equal)
Span_1000Tags-2                                      11.0 ± 0%      11.0 ± 0%     ~     (all samples are equal)
Span_100BaggageItems-2                               11.0 ± 0%      11.0 ± 0%     ~     (all samples are equal)
TrimmedSpan_100Events_100Tags_100BaggageItems-2     0.00 ±NaN%     0.00 ±NaN%     ~     (all samples are equal)
Inject_TextMap_Empty-2                               6.00 ± 0%      6.00 ± 0%     ~     (all samples are equal)
Inject_TextMap_100BaggageItems-2                      206 ± 0%       206 ± 0%     ~     (all samples are equal)
Inject_Binary_Empty-2                                9.00 ± 0%      5.00 ± 0%  -44.44%        (p=0.000 n=10+10)
Inject_Binary_100BaggageItems-2                       409 ± 0%         5 ± 0%  -98.78%        (p=0.000 n=10+10)
Join_TextMap_Empty-2                                 14.0 ± 0%      14.0 ± 0%     ~     (all samples are equal)
Join_TextMap_100BaggageItems-2                        424 ± 0%       424 ± 0%     ~     (all samples are equal)
Join_Binary_Empty-2                                  10.0 ± 0%       6.0 ± 0%  -40.00%        (p=0.000 n=10+10)
Join_Binary_100BaggageItems-2                         618 ± 0%       217 ± 0%  -64.89%        (p=0.000 n=10+10)
```

Use sfixed64 in the proto file per feedback

Add test for ProtobufCarrier

Reflect carrier simplification changes

Ignore autogenerated protobuf files in CI

TravisCI currently fails since the autogenerated protobuf files don't
pass golint. The patch performs an inverted match on the golint output,
allowing for `*.pb.go` files to be ignored.
  • Loading branch information
bg451 committed Mar 24, 2016
1 parent e79a6e4 commit d59c365
Show file tree
Hide file tree
Showing 7 changed files with 636 additions and 85 deletions.
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ bench:

.PHONY: lint
lint:
golint ./...
@# Run again with magic to exit non-zero if golint outputs anything.
@! (golint ./... | read dummy)
# Ignore grep's exit code since no match returns 1.
-golint ./... | grep --invert-match -E '^.*\.pb\.go'
@
@! (golint ./... |grep --invert-match -E '^.*\.pb\.go' | read dummy)

.PHONY: vet
vet:
Expand Down
114 changes: 32 additions & 82 deletions propagation_ot.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package basictracer

import (
"bytes"
"encoding/binary"
"io"
"strconv"
"strings"
"time"

"github.com/gogo/protobuf/proto"
"github.com/opentracing/basictracer-go/wire"
opentracing "github.com/opentracing/opentracing-go"
)

Expand Down Expand Up @@ -134,50 +135,26 @@ func (p *binaryPropagator) Inject(
if !ok {
return opentracing.ErrInvalidCarrier
}
var err error
var sampledByte byte
if sc.raw.Sampled {
sampledByte = 1
}

// Handle the trace and span ids, and sampled status.
err = binary.Write(carrier, binary.BigEndian, sc.raw.TraceID)
if err != nil {
return err
}
state := wire.TracerState{}
state.TraceId = sc.raw.TraceID
state.SpanId = sc.raw.SpanID
state.Sampled = sc.raw.Sampled
state.BaggageItems = sc.raw.Baggage

err = binary.Write(carrier, binary.BigEndian, sc.raw.SpanID)
b, err := proto.Marshal(&state)
if err != nil {
return err
}

err = binary.Write(carrier, binary.BigEndian, sampledByte)
if err != nil {
// Write the length of the marshalled binary to the writer.
length := uint32(len(b))
if err := binary.Write(carrier, binary.BigEndian, &length); err != nil {
return err
}

// Handle the baggage.
err = binary.Write(carrier, binary.BigEndian, int32(len(sc.raw.Baggage)))
if err != nil {
return err
}
for key, val := range sc.raw.Baggage {
if err = binary.Write(carrier, binary.BigEndian, int32(len(key))); err != nil {
return err
}
if _, err = io.WriteString(carrier, key); err != nil {
return err
}

if err = binary.Write(carrier, binary.BigEndian, int32(len(val))); err != nil {
return err
}
if _, err = io.WriteString(carrier, val); err != nil {
return err
}
}

return nil
_, err = carrier.Write(b)
return err
}

func (p *binaryPropagator) Join(
Expand All @@ -188,66 +165,39 @@ func (p *binaryPropagator) Join(
if !ok {
return nil, opentracing.ErrInvalidCarrier
}
// Handle the trace, span ids, and sampled status.
var traceID, propagatedSpanID int64
var sampledByte byte

if err := binary.Read(carrier, binary.BigEndian, &traceID); err != nil {
if err == io.EOF {
return nil, opentracing.ErrTraceNotFound
}
return nil, opentracing.ErrTraceCorrupted
}
if err := binary.Read(carrier, binary.BigEndian, &propagatedSpanID); err != nil {
// Read the length of marshalled binary. io.ReadAll isn't that performant
// since it keeps resizing the underlying buffer as it encounters more bytes
// to read. By reading the length, we can allocate a fixed sized buf and read
// the exact amount of bytes into it.
var length uint32
if err := binary.Read(carrier, binary.BigEndian, &length); err != nil {
return nil, opentracing.ErrTraceCorrupted
}
if err := binary.Read(carrier, binary.BigEndian, &sampledByte); err != nil {
return nil, opentracing.ErrTraceCorrupted
buf := make([]byte, length)
if n, err := carrier.Read(buf); err != nil {
if n > 0 {
return nil, opentracing.ErrTraceCorrupted
}
return nil, opentracing.ErrTraceNotFound
}

// Handle the baggage.
var numBaggage int32
if err := binary.Read(carrier, binary.BigEndian, &numBaggage); err != nil {
ctx := wire.TracerState{}
if err := proto.Unmarshal(buf, &ctx); err != nil {
return nil, opentracing.ErrTraceCorrupted
}
iNumBaggage := int(numBaggage)
var baggageMap map[string]string
if iNumBaggage > 0 {
var buf bytes.Buffer // TODO(tschottdorf): candidate for sync.Pool
baggageMap = make(map[string]string, iNumBaggage)
var keyLen, valLen int32
for i := 0; i < iNumBaggage; i++ {
if err := binary.Read(carrier, binary.BigEndian, &keyLen); err != nil {
return nil, opentracing.ErrTraceCorrupted
}
buf.Grow(int(keyLen))
if n, err := io.CopyN(&buf, carrier, int64(keyLen)); err != nil || int32(n) != keyLen {
return nil, opentracing.ErrTraceCorrupted
}
key := buf.String()
buf.Reset()

if err := binary.Read(carrier, binary.BigEndian, &valLen); err != nil {
return nil, opentracing.ErrTraceCorrupted
}
if n, err := io.CopyN(&buf, carrier, int64(valLen)); err != nil || int32(n) != valLen {
return nil, opentracing.ErrTraceCorrupted
}
baggageMap[key] = buf.String()
buf.Reset()
}
}

sp := p.tracer.getSpan()
sp.raw = RawSpan{
Context: Context{
TraceID: traceID,
TraceID: ctx.TraceId,
SpanID: randomID(),
ParentSpanID: propagatedSpanID,
Sampled: sampledByte != 0,
ParentSpanID: ctx.SpanId,
Sampled: ctx.Sampled,
},
}
sp.raw.Baggage = baggageMap

sp.raw.Baggage = ctx.BaggageItems

return p.tracer.startSpanInternal(
sp,
Expand Down
40 changes: 40 additions & 0 deletions wire/carrier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package wire

// ProtobufCarrier is a DelegatingCarrier that uses protocol buffers as the
// the underlying datastructure. The reason for implementing DelagatingCarrier
// is to allow for end users to serialize the underlying protocol buffers using
// jsonpb or any other serialization forms they want.
type ProtobufCarrier TracerState

// SetState set's the tracer state.
func (p *ProtobufCarrier) SetState(traceID, spanID int64, sampled bool) {
p.TraceId = traceID
p.SpanId = spanID
p.Sampled = sampled
}

// State returns the tracer state.
func (p *ProtobufCarrier) State() (traceID, spanID int64, sampled bool) {
traceID = p.TraceId
spanID = p.SpanId
sampled = p.Sampled
return traceID, spanID, sampled
}

// SetBaggageItem sets a baggage item.
func (p *ProtobufCarrier) SetBaggageItem(key, value string) {
if p.BaggageItems == nil {
p.BaggageItems = map[string]string{key: value}
return
}

p.BaggageItems[key] = value
}

// GetBaggage iterates over each baggage item and executes the callback with
// the key:value pair.
func (p *ProtobufCarrier) GetBaggage(f func(k, v string)) {
for k, v := range p.BaggageItems {
f(k, v)
}
}
38 changes: 38 additions & 0 deletions wire/carrier_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package wire_test

import (
"testing"

"github.com/opentracing/basictracer-go"
"github.com/opentracing/basictracer-go/wire"
)

func TestProtobufCarrier(t *testing.T) {
var carrier basictracer.DelegatingCarrier = &wire.ProtobufCarrier{}

var traceID, spanID int64 = 1, 2
sampled := true
baggageKey, expVal := "key1", "val1"

carrier.SetState(traceID, spanID, sampled)
carrier.SetBaggageItem(baggageKey, expVal)
gotTraceID, gotSpanID, gotSampled := carrier.State()
if traceID != gotTraceID || spanID != gotSpanID || sampled != gotSampled {
t.Errorf("Wanted state %d %d %t, got %d %d %t", spanID, traceID, sampled,
gotTraceID, gotSpanID, gotSampled)
}

gotBaggage := map[string]string{}
f := func(k, v string) {
gotBaggage[k] = v
}

carrier.GetBaggage(f)
value, ok := gotBaggage[baggageKey]
if !ok {
t.Errorf("Expected baggage item %s to exist", baggageKey)
}
if value != expVal {
t.Errorf("Expected key %s to be %s, got %s", baggageKey, expVal, value)
}
}
6 changes: 6 additions & 0 deletions wire/gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package wire

//go:generate protoc --gogofaster_out=$GOPATH/src/github.com/opentracing/basictracer-go/wire wire.proto

// Run `go get github.com/gogo/protobuf/protoc-gen-gogofaster` to install the
// gogofaster generator binary.
Loading

0 comments on commit d59c365

Please sign in to comment.