swarm: integrate OpenTracing; propagate ctx to internal APIs (#17169)

* swarm: propagate ctx, enable opentracing

* swarm/tracing: log error when tracing is misconfigured
This commit is contained in:
Anton Evangelatov
2018-07-13 17:40:28 +02:00
committed by Balint Gabor
parent f7d3678c28
commit 7c9314f231
170 changed files with 21762 additions and 249 deletions

View File

@ -29,6 +29,8 @@ devp2p subprotocols by abstracting away code standardly shared by protocols.
package protocols
import (
"bufio"
"bytes"
"context"
"fmt"
"io"
@ -39,6 +41,10 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/swarm/spancontext"
"github.com/ethereum/go-ethereum/swarm/tracing"
opentracing "github.com/opentracing/opentracing-go"
)
// error codes used by this protocol scheme
@ -109,6 +115,13 @@ func errorf(code int, format string, params ...interface{}) *Error {
}
}
// WrappedMsg is used to propagate marshalled context alongside message payloads
type WrappedMsg struct {
Context []byte
Size uint32
Payload []byte
}
// Spec is a protocol specification including its name and version as well as
// the types of messages which are exchanged
type Spec struct {
@ -201,7 +214,7 @@ func NewPeer(p *p2p.Peer, rw p2p.MsgReadWriter, spec *Spec) *Peer {
// the handler argument is a function which is called for each message received
// from the remote peer, a returned error causes the loop to exit
// resulting in disconnection
func (p *Peer) Run(handler func(msg interface{}) error) error {
func (p *Peer) Run(handler func(ctx context.Context, msg interface{}) error) error {
for {
if err := p.handleIncoming(handler); err != nil {
if err != io.EOF {
@ -225,14 +238,47 @@ func (p *Peer) Drop(err error) {
// message off to the peer
// this low level call will be wrapped by libraries providing routed or broadcast sends
// but often just used to forward and push messages to directly connected peers
func (p *Peer) Send(msg interface{}) error {
func (p *Peer) Send(ctx context.Context, msg interface{}) error {
defer metrics.GetOrRegisterResettingTimer("peer.send_t", nil).UpdateSince(time.Now())
metrics.GetOrRegisterCounter("peer.send", nil).Inc(1)
var b bytes.Buffer
if tracing.Enabled {
writer := bufio.NewWriter(&b)
tracer := opentracing.GlobalTracer()
sctx := spancontext.FromContext(ctx)
if sctx != nil {
err := tracer.Inject(
sctx,
opentracing.Binary,
writer)
if err != nil {
return err
}
}
writer.Flush()
}
r, err := rlp.EncodeToBytes(msg)
if err != nil {
return err
}
wmsg := WrappedMsg{
Context: b.Bytes(),
Size: uint32(len(r)),
Payload: r,
}
code, found := p.spec.GetCode(msg)
if !found {
return errorf(ErrInvalidMsgType, "%v", code)
}
return p2p.Send(p.rw, code, msg)
return p2p.Send(p.rw, code, wmsg)
}
// handleIncoming(code)
@ -243,7 +289,7 @@ func (p *Peer) Send(msg interface{}) error {
// * checks for out-of-range message codes,
// * handles decoding with reflection,
// * call handlers as callbacks
func (p *Peer) handleIncoming(handle func(msg interface{}) error) error {
func (p *Peer) handleIncoming(handle func(ctx context.Context, msg interface{}) error) error {
msg, err := p.rw.ReadMsg()
if err != nil {
return err
@ -255,11 +301,38 @@ func (p *Peer) handleIncoming(handle func(msg interface{}) error) error {
return errorf(ErrMsgTooLong, "%v > %v", msg.Size, p.spec.MaxMsgSize)
}
// unmarshal wrapped msg, which might contain context
var wmsg WrappedMsg
err = msg.Decode(&wmsg)
if err != nil {
log.Error(err.Error())
return err
}
ctx := context.Background()
// if tracing is enabled and the context coming within the request is
// not empty, try to unmarshal it
if tracing.Enabled && len(wmsg.Context) > 0 {
var sctx opentracing.SpanContext
tracer := opentracing.GlobalTracer()
sctx, err = tracer.Extract(
opentracing.Binary,
bytes.NewReader(wmsg.Context))
if err != nil {
log.Error(err.Error())
return err
}
ctx = spancontext.WithContext(ctx, sctx)
}
val, ok := p.spec.NewMsg(msg.Code)
if !ok {
return errorf(ErrInvalidMsgCode, "%v", msg.Code)
}
if err := msg.Decode(val); err != nil {
if err := rlp.DecodeBytes(wmsg.Payload, val); err != nil {
return errorf(ErrDecode, "<= %v: %v", msg, err)
}
@ -268,7 +341,7 @@ func (p *Peer) handleIncoming(handle func(msg interface{}) error) error {
// which the handler is supposed to cast to the appropriate type
// it is entirely safe not to check the cast in the handler since the handler is
// chosen based on the proper type in the first place
if err := handle(val); err != nil {
if err := handle(ctx, val); err != nil {
return errorf(ErrHandler, "(msg code %v): %v", msg.Code, err)
}
return nil
@ -288,14 +361,14 @@ func (p *Peer) Handshake(ctx context.Context, hs interface{}, verify func(interf
return nil, errorf(ErrHandshake, "unknown handshake message type: %T", hs)
}
errc := make(chan error, 2)
handle := func(msg interface{}) error {
handle := func(ctx context.Context, msg interface{}) error {
rhs = msg
if verify != nil {
return verify(rhs)
}
return nil
}
send := func() { errc <- p.Send(hs) }
send := func() { errc <- p.Send(ctx, hs) }
receive := func() { errc <- p.handleIncoming(handle) }
go func() {