Repository: scionproto/scion
Pull request #3544 (2019-12-18 16:15:16)

Tracing: Add span logger
This PR adds a span logger that implements the log.Logger interface.
The span logger logs to file and additionally attaches the log entry
to the current span in the context.

Additionally:
- Add tracing ID transfer in the sciond API
- Add tracing support to the cert_req and end2end integration tests
- Add log statements to the trust store
- Unify the logger setup between sciond API, quic and legacy msgr
- Update jaeger version

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/scionproto/scion/3544)
<!-- Reviewable:end -->



Patch:
diff --git a/go/integration/BUILD.bazel b/go/integration/BUILD.bazel
index a0dc90175..bbd54c1db 100644
--- a/go/integration/BUILD.bazel
+++ b/go/integration/BUILD.bazel
@@ -6,10 +6,12 @@ go_library(
     importpath = "github.com/scionproto/scion/go/integration",
     visibility = ["//visibility:public"],
     deps = [
+        "//go/lib/env:go_default_library",
         "//go/lib/integration:go_default_library",
         "//go/lib/log:go_default_library",
         "//go/lib/sciond:go_default_library",
         "//go/lib/snet:go_default_library",
         "//go/lib/sock/reliable:go_default_library",
+        "@com_github_opentracing_opentracing_go//:go_default_library",
     ],
 )
diff --git a/go/integration/cert_req/BUILD.bazel b/go/integration/cert_req/BUILD.bazel
index a05068e43..8aa4247ba 100644
--- a/go/integration/cert_req/BUILD.bazel
+++ b/go/integration/cert_req/BUILD.bazel
@@ -20,6 +20,7 @@ go_library(
         "//go/lib/scrypto/cert/v2:go_default_library",
         "//go/lib/scrypto/trc/v2:go_default_library",
         "//go/lib/snet:go_default_library",
+        "//go/lib/tracing:go_default_library",
     ],
 )
 
diff --git a/go/integration/cert_req/main.go b/go/integration/cert_req/main.go
index 11ffc608b..ff7038275 100644
--- a/go/integration/cert_req/main.go
+++ b/go/integration/cert_req/main.go
@@ -34,6 +34,7 @@ import (
 	"github.com/scionproto/scion/go/lib/scrypto/cert/v2"
 	"github.com/scionproto/scion/go/lib/scrypto/trc/v2"
 	"github.com/scionproto/scion/go/lib/snet"
+	"github.com/scionproto/scion/go/lib/tracing"
 )
 
 var (
@@ -50,6 +51,13 @@ func realMain() int {
 	defer log.Flush()
 	addFlags()
 	integration.Setup()
+
+	closeTracer, err := integration.InitTracer("cert_req")
+	if err != nil {
+		log.Crit("Unable to create tracer", "err", err)
+		return 1
+	}
+	defer closeTracer()
 	return client{}.run()
 }
 
@@ -92,28 +100,35 @@ func (c client) run() int {
 }
 
 func (c client) attemptRequest(n int) bool {
+	span, ctx := tracing.CtxWith(context.Background(), "run")
+	span.SetTag("attempt", n)
+	span.SetTag("src", integration.Local.IA)
+	span.SetTag("subject", remoteIA)
+	defer span.Finish()
+
 	// Send certchain request
 	var chain *cert.Chain
 	var err error
-	if chain, err = c.requestCert(); err != nil {
+	if chain, err = c.requestCert(ctx); err != nil {
 		log.Error("Error requesting certificate chain", "err", err)
 		return false
 	}
 	// Send TRC request
-	if err = c.requestTRC(chain); err != nil {
+	if err = c.requestTRC(ctx, chain); err != nil {
 		log.Error("Error requesting TRC", "err", err)
 		return false
 	}
 	return true
 }
 
-func (c client) requestCert() (*cert.Chain, error) {
+func (c client) requestCert(parentCtx context.Context) (*cert.Chain, error) {
+	logger := log.FromCtx(parentCtx)
 	req := &cert_mgmt.ChainReq{
 		RawIA:   remoteIA.IAInt(),
 		Version: scrypto.LatestVer,
 	}
-	log.Info("Request to SVC: Chain request", "req", req, "svc", svc)
-	ctx, cancelF := context.WithTimeout(context.Background(), integration.DefaultIOTimeout)
+	logger.Info("Request to SVC: Chain request", "req", req, "svc", svc)
+	ctx, cancelF := context.WithTimeout(parentCtx, integration.DefaultIOTimeout)
 	defer cancelF()
 	rawChain, err := c.msgr.GetCertChain(ctx, req, &svc, messenger.NextId())
 	if err != nil {
@@ -131,17 +146,18 @@ func (c client) requestCert() (*cert.Chain, error) {
 		return nil, common.NewBasicError("Invalid subject", nil,
 			"expected", remoteIA, "actual", as.Subject)
 	}
-	log.Info("Response from SVC: Correct chain", "chain", chain)
+	logger.Info("Response from SVC: Correct chain", "chain", chain)
 	return &chain, nil
 }
 
-func (c client) requestTRC(chain *cert.Chain) error {
+func (c client) requestTRC(parentCtx context.Context, chain *cert.Chain) error {
+	logger := log.FromCtx(parentCtx)
 	req := &cert_mgmt.TRCReq{
 		ISD:     remoteIA.I,
 		Version: scrypto.LatestVer,
 	}
-	log.Info("Request to SVC: TRC request", "req", req, "svc", svc)
-	ctx, cancelF := context.WithTimeout(context.Background(), integration.DefaultIOTimeout)
+	logger.Info("Request to SVC: TRC request", "req", req, "svc", svc)
+	ctx, cancelF := context.WithTimeout(parentCtx, integration.DefaultIOTimeout)
 	defer cancelF()
 	rawTrc, err := c.msgr.GetTRC(ctx, req, &svc, messenger.NextId())
 	if err != nil {
@@ -162,7 +178,7 @@ func (c client) requestTRC(chain *cert.Chain) error {
 	if err := c.verifyChain(chain, trc); err != nil {
 		return common.NewBasicError("unable to verify chain", err)
 	}
-	log.Info("Response from SVC: Correct TRC", "TRC", trc)
+	logger.Info("Response from SVC: Correct TRC", "TRC", trc)
 	return nil
 }
 
diff --git a/go/integration/common.go b/go/integration/common.go
index 4793e6b92..e677c3a03 100644
--- a/go/integration/common.go
+++ b/go/integration/common.go
@@ -22,6 +22,9 @@ import (
 	"os"
 	"time"
 
+	"github.com/opentracing/opentracing-go"
+
+	"github.com/scionproto/scion/go/lib/env"
 	"github.com/scionproto/scion/go/lib/integration"
 	"github.com/scionproto/scion/go/lib/log"
 	"github.com/scionproto/scion/go/lib/sciond"
@@ -55,6 +58,26 @@ func addFlags() {
 	log.AddLogConsFlags()
 }
 
+// InitTracer initializes the global tracer and returns a closer function.
+func InitTracer(name string) (func(), error) {
+	cfg := &env.Tracing{
+		Enabled: true,
+		Debug:   true,
+	}
+	cfg.InitDefaults()
+	tr, closer, err := cfg.NewTracer(name)
+	if err != nil {
+		return nil, err
+	}
+	opentracing.SetGlobalTracer(tr)
+	closeTracer := func() {
+		if err := closer.Close(); err != nil {
+			log.Error("Unable to close tracer", "err", err)
+		}
+	}
+	return closeTracer, nil
+}
+
 func validateFlags() {
 	flag.Parse()
 	if err := log.SetupFromFlags(""); err != nil {
diff --git a/go/integration/end2end/BUILD.bazel b/go/integration/end2end/BUILD.bazel
index 3d143b43f..827f49a64 100644
--- a/go/integration/end2end/BUILD.bazel
+++ b/go/integration/end2end/BUILD.bazel
@@ -19,6 +19,7 @@ go_library(
         "//go/lib/snet:go_default_library",
         "//go/lib/sock/reliable:go_default_library",
         "//go/lib/topology:go_default_library",
+        "//go/lib/tracing:go_default_library",
         "//go/lib/util:go_default_library",
     ],
 )
diff --git a/go/integration/end2end/main.go b/go/integration/end2end/main.go
index 32cfccd09..636253a11 100644
--- a/go/integration/end2end/main.go
+++ b/go/integration/end2end/main.go
@@ -36,6 +36,7 @@ import (
 	"github.com/scionproto/scion/go/lib/snet"
 	"github.com/scionproto/scion/go/lib/sock/reliable"
 	"github.com/scionproto/scion/go/lib/topology"
+	"github.com/scionproto/scion/go/lib/tracing"
 	"github.com/scionproto/scion/go/lib/util"
 )
 
@@ -59,6 +60,13 @@ func realMain() int {
 	addFlags()
 	integration.Setup()
 	validateFlags()
+
+	closeTracer, err := integration.InitTracer("end_2_end")
+	if err != nil {
+		log.Crit("Unable to create tracer", "err", err)
+		return 1
+	}
+	defer closeTracer()
 	if integration.Mode == integration.ModeServer {
 		server{}.run()
 		return 0
@@ -165,18 +173,26 @@ func (c client) run() int {
 }
 
 func (c client) attemptRequest(n int) bool {
-	ctx, cancel := context.WithTimeout(context.Background(), timeout.Duration)
+	timeoutCtx, cancel := context.WithTimeout(context.Background(), timeout.Duration)
 	defer cancel()
+	span, ctx := tracing.CtxWith(timeoutCtx, "run")
+	span.SetTag("attempt", n)
+	span.SetTag("src", integration.Local.IA)
+	span.SetTag("dst", remote.IA)
+	defer span.Finish()
+	logger := log.FromCtx(ctx)
+
 	// Send ping
 	if err := c.ping(ctx, n); err != nil {
-		log.Error("Could not send packet", "err", err)
+		logger.Error("Could not send packet", "err", err)
 		return false
 	}
 	// Receive pong
 	if err := c.pong(ctx); err != nil {
-		log.Debug("Error receiving pong", "err", err)
+		logger.Debug("Error receiving pong", "err", err)
 		return false
 	}
+	logger.Info("Received pong")
 	return true
 }
 
diff --git a/go/lib/infra/messenger/BUILD.bazel b/go/lib/infra/messenger/BUILD.bazel
index b4bf610dc..593fb26a7 100644
--- a/go/lib/infra/messenger/BUILD.bazel
+++ b/go/lib/infra/messenger/BUILD.bazel
@@ -35,7 +35,6 @@ go_library(
         "//go/lib/svc:go_default_library",
         "//go/lib/topology:go_default_library",
         "//go/lib/tracing:go_default_library",
-        "//go/lib/util:go_default_library",
         "//go/proto:go_default_library",
         "@com_github_lucas_clemente_quic_go//:go_default_library",
         "@com_github_opentracing_opentracing_go//:go_default_library",
diff --git a/go/lib/infra/messenger/messenger.go b/go/lib/infra/messenger/messenger.go
index 00b0e4d5c..d6de06a42 100644
--- a/go/lib/infra/messenger/messenger.go
+++ b/go/lib/infra/messenger/messenger.go
@@ -101,7 +101,7 @@ import (
 	"github.com/scionproto/scion/go/lib/infra/rpc"
 	"github.com/scionproto/scion/go/lib/log"
 	"github.com/scionproto/scion/go/lib/snet"
-	"github.com/scionproto/scion/go/lib/util"
+	"github.com/scionproto/scion/go/lib/tracing"
 	"github.com/scionproto/scion/go/proto"
 )
 
@@ -127,9 +127,6 @@ type Config struct {
 	// verification of the top level signature in received signed control
 	// payloads.
 	DisableSignatureVerification bool
-	// Logger is used for internal Messenger logging. If it is nil, the default
-	// root logger is used.
-	Logger log.Logger
 	// QUIC defines whether the Messenger should also operate on top of QUIC
 	// instead of only on UDP.
 	QUIC *QUICConfig
@@ -145,9 +142,6 @@ func (c *Config) InitDefaults() {
 	if c.HandlerTimeout == 0 {
 		c.HandlerTimeout = DefaultHandlerTimeout
 	}
-	if c.Logger == nil {
-		c.Logger = log.Root()
-	}
 }
 
 var _ infra.Messenger = (*Messenger)(nil)
@@ -179,8 +173,7 @@ type Messenger struct {
 	ctx     context.Context
 	cancelF context.CancelFunc
 
-	ia  addr.IA
-	log log.Logger
+	ia addr.IA
 
 	quicClient  *rpc.Client
 	quicServer  *rpc.Server
@@ -208,10 +201,9 @@ func New(config *Config) *Messenger {
 			QUICConfig: config.QUIC.QUICConfig,
 		}
 		quicHandler = &QUICHandler{
-			handlers:     make(map[infra.MessageType]infra.Handler),
-			timeout:      config.HandlerTimeout,
-			parentLogger: config.Logger,
-			parentCtx:    ctx,
+			handlers:  make(map[infra.MessageType]infra.Handler),
+			timeout:   config.HandlerTimeout,
+			parentCtx: ctx,
 		}
 		quicServer = &rpc.Server{
 			Conn:       config.QUIC.Conn,
@@ -237,7 +229,6 @@ func New(config *Config) *Messenger {
 		closeChan:       make(chan struct{}),
 		ctx:             ctx,
 		cancelF:         cancelF,
-		log:             config.Logger,
 		quicServer:      quicServer,
 		quicClient:      quicClient,
 		quicHandler:     quicHandler,
@@ -257,7 +248,8 @@ func (m *Messenger) SendAck(ctx context.Context, msg *ack.Ack, a net.Addr, id ui
 func (m *Messenger) GetTRC(ctx context.Context, msg *cert_mgmt.TRCReq,
 	a net.Addr, id uint64) (*cert_mgmt.TRC, error) {
 
-	pld, err := ctrl.NewCertMgmtPld(msg, nil, &ctrl.Data{ReqId: id, TraceId: traceId(ctx)})
+	data := &ctrl.Data{ReqId: id, TraceId: tracing.IDFromCtx(ctx)}
+	pld, err := ctrl.NewCertMgmtPld(msg, nil, data)
 	if err != nil {
 		return nil, err
 	}
@@ -297,7 +289,8 @@ func (m *Messenger) GetCertChain(ctx context.Context, msg *cert_mgmt.ChainReq,
 	a net.Addr, id uint64) (*cert_mgmt.Chain, error) {
 
 	logger := log.FromCtx(ctx)
-	pld, err := ctrl.NewCertMgmtPld(msg, nil, &ctrl.Data{ReqId: id, TraceId: traceId(ctx)})
+	data := &ctrl.Data{ReqId: id, TraceId: tracing.IDFromCtx(ctx)}
+	pld, err := ctrl.NewCertMgmtPld(msg, nil, data)
 	if err != nil {
 		return nil, err
 	}
@@ -341,7 +334,8 @@ func (m *Messenger) SendIfId(ctx context.Context, msg *ifid.IFID, a net.Addr, id
 func (m *Messenger) SendIfStateInfos(ctx context.Context, msg *path_mgmt.IFStateInfos,
 	a net.Addr, id uint64) error {
 
-	pld, err := ctrl.NewPathMgmtPld(msg, nil, &ctrl.Data{ReqId: id, TraceId: traceId(ctx)})
+	data := &ctrl.Data{ReqId: id, TraceId: tracing.IDFromCtx(ctx)}
+	pld, err := ctrl.NewPathMgmtPld(msg, nil, data)
 	if err != nil {
 		return err
 	}
@@ -372,25 +366,12 @@ func (m *Messenger) SendSegReg(ctx context.Context, msg *path_mgmt.SegReg,
 	return m.sendMessage(ctx, pld, a, id, infra.SegReg)
 }
 
-func traceId(ctx context.Context) common.RawBytes {
-	span := opentracing.SpanFromContext(ctx)
-	tracer := opentracing.GlobalTracer()
-	if span != nil && tracer != nil {
-		var tracingBin bytes.Buffer
-		err := tracer.Inject(span.Context(), opentracing.Binary, &tracingBin)
-		if err != nil {
-			panic(err)
-		}
-		return tracingBin.Bytes()
-	}
-	return nil
-}
-
 func (m *Messenger) GetSegs(ctx context.Context, msg *path_mgmt.SegReq,
 	a net.Addr, id uint64) (*path_mgmt.SegReply, error) {
 
 	logger := log.FromCtx(ctx)
-	pld, err := ctrl.NewPathMgmtPld(msg, nil, &ctrl.Data{ReqId: id, TraceId: traceId(ctx)})
+	data := &ctrl.Data{ReqId: id, TraceId: tracing.IDFromCtx(ctx)}
+	pld, err := ctrl.NewPathMgmtPld(msg, nil, data)
 	if err != nil {
 		return nil, err
 	}
@@ -446,7 +427,8 @@ func (m *Messenger) GetSegChangesIds(ctx context.Context, msg *path_mgmt.SegChan
 	a net.Addr, id uint64) (*path_mgmt.SegChangesIdReply, error) {
 
 	logger := log.FromCtx(ctx)
-	pld, err := ctrl.NewPathMgmtPld(msg, nil, &ctrl.Data{ReqId: id, TraceId: traceId(ctx)})
+	data := &ctrl.Data{ReqId: id, TraceId: tracing.IDFromCtx(ctx)}
+	pld, err := ctrl.NewPathMgmtPld(msg, nil, data)
 	if err != nil {
 		return nil, err
 	}
@@ -490,7 +472,8 @@ func (m *Messenger) GetSegChanges(ctx context.Context, msg *path_mgmt.SegChanges
 	a net.Addr, id uint64) (*path_mgmt.SegChangesReply, error) {
 
 	logger := log.FromCtx(ctx)
-	pld, err := ctrl.NewPathMgmtPld(msg, nil, &ctrl.Data{ReqId: id, TraceId: traceId(ctx)})
+	data := &ctrl.Data{ReqId: id, TraceId: tracing.IDFromCtx(ctx)}
+	pld, err := ctrl.NewPathMgmtPld(msg, nil, data)
 	if err != nil {
 		return nil, err
 	}
@@ -547,7 +530,8 @@ func (m *Messenger) GetHPSegs(ctx context.Context, msg *path_mgmt.HPSegReq, a ne
 	id uint64) (*path_mgmt.HPSegReply, error) {
 
 	logger := log.FromCtx(ctx)
-	pld, err := ctrl.NewPathMgmtPld(msg, nil, &ctrl.Data{ReqId: id, TraceId: traceId(ctx)})
+	data := &ctrl.Data{ReqId: id, TraceId: tracing.IDFromCtx(ctx)}
+	pld, err := ctrl.NewPathMgmtPld(msg, nil, data)
 	if err != nil {
 		return nil, err
 	}
@@ -593,7 +577,8 @@ func (m *Messenger) GetHPCfgs(ctx context.Context, msg *path_mgmt.HPCfgReq, a ne
 	id uint64) (*path_mgmt.HPCfgReply, error) {
 
 	logger := log.FromCtx(ctx)
-	pld, err := ctrl.NewPathMgmtPld(msg, nil, &ctrl.Data{ReqId: id, TraceId: traceId(ctx)})
+	data := &ctrl.Data{ReqId: id, TraceId: tracing.IDFromCtx(ctx)}
+	pld, err := ctrl.NewPathMgmtPld(msg, nil, data)
 	if err != nil {
 		return nil, err
 	}
@@ -636,7 +621,8 @@ func (m *Messenger) RequestChainIssue(ctx context.Context, msg *cert_mgmt.ChainI
 	id uint64) (*cert_mgmt.ChainIssRep, error) {
 
 	logger := log.FromCtx(ctx)
-	pld, err := ctrl.NewCertMgmtPld(msg, nil, &ctrl.Data{ReqId: id, TraceId: traceId(ctx)})
+	data := &ctrl.Data{ReqId: id, TraceId: tracing.IDFromCtx(ctx)}
+	pld, err := ctrl.NewCertMgmtPld(msg, nil, data)
 	if err != nil {
 		return nil, err
 	}
@@ -687,7 +673,7 @@ func (m *Messenger) SendBeacon(ctx context.Context, msg *seg.Beacon, a net.Addr,
 		return common.NewBasicError("[Messenger] Cannot send to unknown address", nil)
 	}
 
-	pld, err := ctrl.NewPld(msg, &ctrl.Data{ReqId: id, TraceId: traceId(ctx)})
+	pld, err := ctrl.NewPld(msg, &ctrl.Data{ReqId: id, TraceId: tracing.IDFromCtx(ctx)})
 	if err != nil {
 		return err
 	}
@@ -721,7 +707,7 @@ func (m *Messenger) SendBeacon(ctx context.Context, msg *seg.Beacon, a net.Addr,
 func (m *Messenger) sendMessage(ctx context.Context, msg proto.Cerealizable, a net.Addr,
 	id uint64, msgType infra.MessageType) error {
 
-	pld, err := ctrl.NewPld(msg, &ctrl.Data{ReqId: id, TraceId: traceId(ctx)})
+	pld, err := ctrl.NewPld(msg, &ctrl.Data{ReqId: id, TraceId: tracing.IDFromCtx(ctx)})
 	if err != nil {
 		return err
 	}
@@ -758,16 +744,16 @@ func (m *Messenger) ListenAndServe() {
 }
 
 func (m *Messenger) listenAndServeQUIC() {
-	m.log.Info("Started listening QUIC")
-	defer m.log.Info("Stopped listening QUIC")
+	log.Info("Started listening QUIC")
+	defer log.Info("Stopped listening QUIC")
 	if err := m.quicServer.ListenAndServe(); err != nil {
-		m.log.Error("QUIC server listen error", "err", err)
+		log.Error("QUIC server listen error", "err", err)
 	}
 }
 
 func (m *Messenger) listenAndServeUDP() {
-	m.log.Info("Started listening UDP")
-	defer m.log.Info("Stopped listening UDP")
+	log.Info("Started listening UDP")
+	defer log.Info("Stopped listening UDP")
 	for {
 		// Recv blocks until a new message is received. To close the server,
 		// CloseServer() calls the context's cancel function, thus unblocking Recv. The
@@ -782,17 +768,14 @@ func (m *Messenger) listenAndServeUDP() {
 				return
 			default:
 				metrics.Dispatcher.Reads(metrics.ResultLabels{Result: metrics.ErrRead}).Inc()
-				m.log.Error("Receive error", "err", err)
+				log.Error("Receive error", "err", err)
 			}
 			continue
 		}
-		debugId := util.GetDebugID()
-		logger := m.log.New("debug_id", debugId)
-
 		signedPld, ok := genericMsg.(*ctrl.SignedPld)
 		if !ok {
 			metrics.Dispatcher.Reads(metrics.ResultLabels{Result: metrics.ErrInvalidReq}).Inc()
-			logger.Error("Type assertion failure", "from", address, "expected", "*ctrl.SignedPld",
+			log.Error("Type assertion failure", "from", address, "expected", "*ctrl.SignedPld",
 				"actual", common.TypeOf(genericMsg))
 			continue
 		}
@@ -805,43 +788,58 @@ func (m *Messenger) listenAndServeUDP() {
 			verifier := m.verifier.WithIA(address.(*snet.Addr).IA)
 			if pld, err = signedPld.GetVerifiedPld(serveCtx, verifier); err != nil {
 				metrics.Dispatcher.Reads(metrics.ResultLabels{Result: metrics.ErrVerify}).Inc()
-				logger.Error("Verification error", "from", address, "err", err)
+				log.Error("Verification error", "from", address, "err", err)
 				serveCancelF()
 				continue
 			}
 		} else {
 			if pld, err = signedPld.UnsafePld(); err != nil {
 				metrics.Dispatcher.Reads(metrics.ResultLabels{Result: metrics.ErrParse}).Inc()
-				logger.Error("Unable to extract Pld from CtrlPld", "from", address, "err", err)
+				log.Error("Unable to extract Pld from CtrlPld", "from", address, "err", err)
 				serveCancelF()
 				continue
 			}
 		}
-		serveCtx = log.CtxWith(serveCtx, logger)
 		m.serve(serveCtx, serveCancelF, pld, signedPld, size, address)
 	}
 }
 
-func (m *Messenger) serve(ctx context.Context, cancelF context.CancelFunc, pld *ctrl.Pld,
+func (m *Messenger) serve(parentCtx context.Context, cancelF context.CancelFunc, pld *ctrl.Pld,
 	signedPld *ctrl.SignedPld, size int, address net.Addr) {
 
-	logger := log.FromCtx(ctx)
-	ctx = infra.NewContextWithResponseWriter(ctx,
-		&UDPResponseWriter{
-			Messenger: m,
-			Remote:    address,
-			ID:        pld.ReqId,
-		},
-	)
 	// Validate that the message is of acceptable type, and that its top-level
 	// signature is correct.
 	msgType, msg, err := validate(pld)
 	if err != nil {
 		metrics.Dispatcher.Reads(metrics.ResultLabels{Result: metrics.ErrValidate}).Inc()
-		logger.Error("Received message, but unable to validate message",
+		log.Error("Received message, but unable to validate message",
 			"from", address, "err", err)
 		return
 	}
+
+	rwCtx := infra.NewContextWithResponseWriter(parentCtx,
+		&UDPResponseWriter{
+			Messenger: m,
+			Remote:    address,
+			ID:        pld.ReqId,
+		},
+	)
+
+	// Tracing
+	var spanCtx opentracing.SpanContext
+	if len(pld.Data.TraceId) > 0 {
+		var err error
+		spanCtx, err = opentracing.GlobalTracer().Extract(opentracing.Binary,
+			bytes.NewReader(pld.Data.TraceId))
+		if err != nil {
+			log.Error("Failed to extract span", "err", err)
+		}
+	}
+
+	span, ctx := tracing.CtxWith(rwCtx, fmt.Sprintf("%s-handler-udp", msgType),
+		opentracingext.RPCServerOption(spanCtx))
+	logger := log.FromCtx(ctx)
+
 	logger.Trace("[Messenger] Received message", "type", msgType, "from", address, "id", pld.ReqId)
 
 	m.handlersLock.RLock()
@@ -861,26 +859,10 @@ func (m *Messenger) serve(ctx context.Context, cancelF context.CancelFunc, pld *
 	metrics.Dispatcher.Reads(metrics.ResultLabels{Result: metrics.OkSuccess}).Inc()
 	metrics.Dispatcher.ReadSizes().Observe(float64(size))
 
-	ctx = log.CtxWith(ctx, logger)
-	if tracer := opentracing.GlobalTracer(); tracer != nil {
-		var spanCtx opentracing.SpanContext
-		if pld.Data.TraceId.Len() > 0 {
-			spanCtx, err = tracer.Extract(opentracing.Binary, bytes.NewReader(pld.Data.TraceId))
-			if err != nil {
-				log.Error("Failed to extract span", "err", err)
-			}
-		}
-		var span opentracing.Span
-		span, ctx = opentracing.StartSpanFromContext(ctx,
-			fmt.Sprintf("%s-handler-udp", msgType), opentracingext.RPCServerOption(spanCtx))
-		// TODO(lukedirtwalker) optimally the logger should use the same
-		// debug_id as the span.
-		defer span.Finish()
-	}
-
 	go func() {
 		defer log.LogPanicAndExit()
 		defer cancelF()
+		defer span.Finish()
 		handler.Handle(infra.NewRequest(ctx, msg, signedPld, address, pld.ReqId))
 	}()
 }
diff --git a/go/lib/infra/messenger/quic_handler.go b/go/lib/infra/messenger/quic_handler.go
index 9be077b2a..da392d4a1 100644
--- a/go/lib/infra/messenger/quic_handler.go
+++ b/go/lib/infra/messenger/quic_handler.go
@@ -42,9 +42,8 @@ type QUICHandler struct {
 	handlersLock sync.RWMutex
 	handlers     map[infra.MessageType]infra.Handler
 
-	timeout      time.Duration
-	parentLogger log.Logger
-	parentCtx    context.Context
+	timeout   time.Duration
+	parentCtx context.Context
 }
 
 func (h *QUICHandler) ServeRPC(rw rpc.ReplyWriter, request *rpc.Request) {
@@ -109,9 +108,9 @@ func (h *QUICHandler) prepareServeCtx(pld *ctrl.Pld, messageType infra.MessageTy
 	)
 
 	// Tracing
-	var err error
 	var spanCtx opentracing.SpanContext
-	if pld.Data.TraceId.Len() > 0 {
+	if len(pld.Data.TraceId) > 0 {
+		var err error
 		spanCtx, err = opentracing.GlobalTracer().Extract(opentracing.Binary,
 			bytes.NewReader(pld.Data.TraceId))
 		if err != nil {
@@ -119,10 +118,9 @@ func (h *QUICHandler) prepareServeCtx(pld *ctrl.Pld, messageType infra.MessageTy
 		}
 	}
 
-	var span opentracing.Span
-	serveCtx, span = tracing.CtxWith(serveCtx, h.parentLogger,
-		fmt.Sprintf("%s-handler", messageType), opentracingext.RPCServerOption(spanCtx))
-	return serveCtx, serveCancelF, span
+	span, ctx := tracing.CtxWith(serveCtx, fmt.Sprintf("%s-handler", messageType),
+		opentracingext.RPCServerOption(spanCtx))
+	return ctx, serveCancelF, span
 }
 
 func msgToSignedPld(msg *capnp.Message) (*ctrl.SignedPld, error) {
diff --git a/go/lib/infra/modules/trust/v2/BUILD.bazel b/go/lib/infra/modules/trust/v2/BUILD.bazel
index 7efada00f..56df4297c 100644
--- a/go/lib/infra/modules/trust/v2/BUILD.bazel
+++ b/go/lib/infra/modules/trust/v2/BUILD.bazel
@@ -35,6 +35,8 @@ go_library(
         "//go/lib/serrors:go_default_library",
         "//go/lib/snet:go_default_library",
         "//go/proto:go_default_library",
+        "@com_github_opentracing_opentracing_go//:go_default_library",
+        "@com_github_opentracing_opentracing_go//ext:go_default_library",
         "@org_golang_x_xerrors//:go_default_library",
     ],
 )
diff --git a/go/lib/infra/modules/trust/v2/inserter.go b/go/lib/infra/modules/trust/v2/inserter.go
index 4bb0e8c1a..fa280655e 100644
--- a/go/lib/infra/modules/trust/v2/inserter.go
+++ b/go/lib/infra/modules/trust/v2/inserter.go
@@ -18,6 +18,7 @@ import (
 	"context"
 
 	"github.com/scionproto/scion/go/lib/infra/modules/trust/v2/internal/decoded"
+	"github.com/scionproto/scion/go/lib/log"
 	"github.com/scionproto/scion/go/lib/scrypto/cert/v2"
 	"github.com/scionproto/scion/go/lib/scrypto/trc/v2"
 	"github.com/scionproto/scion/go/lib/serrors"
@@ -97,6 +98,7 @@ type ForwardingInserter struct {
 func (ins ForwardingInserter) InsertTRC(ctx context.Context, decTRC decoded.TRC,
 	trcProvider TRCProviderFunc) error {
 
+	logger := log.FromCtx(ctx)
 	insert, err := ins.shouldInsertTRC(ctx, decTRC, trcProvider)
 	if err != nil {
 		return err
@@ -104,10 +106,15 @@ func (ins ForwardingInserter) InsertTRC(ctx context.Context, decTRC decoded.TRC,
 	if !insert {
 		return nil
 	}
+
 	cs := ins.Router.chooseServer()
+	logger.Debug("[TrustStore:ForwardingInserter] Forward TRC to certificate server",
+		"trc", decTRC, "addr", cs)
 	if err := ins.RPC.SendTRC(ctx, decTRC.Raw, cs); err != nil {
 		return serrors.WrapStr("unable to push TRC to certificate server", err, "addr", cs)
 	}
+	logger.Debug("[TrustStore:ForwardingInserter] Successfully forwarded TRC",
+		"trc", decTRC, "addr", cs)
 	if _, err := ins.DB.InsertTRC(ctx, decTRC); err != nil {
 		return serrors.WrapStr("unable to insert TRC", err)
 	}
@@ -122,6 +129,7 @@ func (ins ForwardingInserter) InsertTRC(ctx context.Context, decTRC decoded.TRC,
 func (ins ForwardingInserter) InsertChain(ctx context.Context, chain decoded.Chain,
 	trcProvider TRCProviderFunc) error {
 
+	logger := log.FromCtx(ctx)
 	insert, err := ins.shouldInsertChain(ctx, chain, trcProvider)
 	if err != nil {
 		return err
@@ -130,9 +138,13 @@ func (ins ForwardingInserter) InsertChain(ctx context.Context, chain decoded.Cha
 		return nil
 	}
 	cs := ins.Router.chooseServer()
+	logger.Debug("[TrustStore:ForwardingInserter] Forward certificate chain to certificate server",
+		"chain", chain, "addr", cs)
 	if err := ins.RPC.SendCertChain(ctx, chain.Raw, cs); err != nil {
 		return serrors.WrapStr("unable to push chain to certificate server", err, "addr", cs)
 	}
+	logger.Debug("[TrustStore:ForwardingInserter] Successfully forwarded certificate chain",
+		"chain", chain)
 	if _, _, err := ins.DB.InsertChain(ctx, chain); err != nil {
 		return serrors.WrapStr("unable to insert chain", err)
 	}
diff --git a/go/lib/infra/modules/trust/v2/inspector.go b/go/lib/infra/modules/trust/v2/inspector.go
index abc96fb65..a1450ff3f 100644
--- a/go/lib/infra/modules/trust/v2/inspector.go
+++ b/go/lib/infra/modules/trust/v2/inspector.go
@@ -17,6 +17,9 @@ package trust
 import (
 	"context"
 
+	"github.com/opentracing/opentracing-go"
+	opentracingext "github.com/opentracing/opentracing-go/ext"
+
 	"github.com/scionproto/scion/go/lib/addr"
 	"github.com/scionproto/scion/go/lib/infra"
 	"github.com/scionproto/scion/go/lib/scrypto"
@@ -41,9 +44,15 @@ type DefaultInspector struct {
 
 // ByAttributes returns a list of primary ASes in the specified ISD that hold
 // all the requested attributes.
-func (i DefaultInspector) ByAttributes(ctx context.Context, isd addr.ISD,
+func (i DefaultInspector) ByAttributes(parentCtx context.Context, isd addr.ISD,
 	opts infra.ASInspectorOpts) ([]addr.IA, error) {
 
+	span, ctx := opentracing.StartSpanFromContext(parentCtx, "by_attributes")
+	defer span.Finish()
+	opentracingext.Component.Set(span, "trust")
+	span.SetTag("isd", isd)
+	span.SetTag("opts", opts)
+
 	trcOpts := infra.TRCOpts{TrustStoreOpts: opts.TrustStoreOpts}
 	t, err := i.Provider.GetTRC(ctx, TRCID{ISD: isd, Version: scrypto.LatestVer}, trcOpts)
 	if err != nil {
@@ -63,6 +72,12 @@ func (i DefaultInspector) ByAttributes(ctx context.Context, isd addr.ISD,
 func (i DefaultInspector) HasAttributes(ctx context.Context, ia addr.IA,
 	opts infra.ASInspectorOpts) (bool, error) {
 
+	span, ctx := opentracing.StartSpanFromContext(ctx, "has_attributes")
+	defer span.Finish()
+	opentracingext.Component.Set(span, "trust")
+	span.SetTag("ia", ia)
+	span.SetTag("opts", opts)
+
 	trcOpts := infra.TRCOpts{TrustStoreOpts: opts.TrustStoreOpts}
 	trc, err := i.Provider.GetTRC(ctx, TRCID{ISD: ia.I, Version: scrypto.LatestVer}, trcOpts)
 	if err != nil {
diff --git a/go/lib/infra/modules/trust/v2/internal/decoded/decode.go b/go/lib/infra/modules/trust/v2/internal/decoded/decode.go
index a4b87551c..4795091b4 100644
--- a/go/lib/infra/modules/trust/v2/internal/decoded/decode.go
+++ b/go/lib/infra/modules/trust/v2/internal/decoded/decode.go
@@ -92,5 +92,5 @@ func (d Chain) String() string {
 	if d.AS == nil {
 		return "<nil>"
 	}
-	return fmt.Sprintf("ISD%s-V%d", d.AS.Subject.FileFmt(true), d.AS.Version)
+	return fmt.Sprintf("ISD%d-AS%s-V%d", d.AS.Subject.I, d.AS.Subject.A, d.AS.Version)
 }
diff --git a/go/lib/infra/modules/trust/v2/provider.go b/go/lib/infra/modules/trust/v2/provider.go
index 99710d3ba..c84d2634c 100644
--- a/go/lib/infra/modules/trust/v2/provider.go
+++ b/go/lib/infra/modules/trust/v2/provider.go
@@ -18,11 +18,14 @@ import (
 	"context"
 	"time"
 
+	"github.com/opentracing/opentracing-go"
+	opentracingext "github.com/opentracing/opentracing-go/ext"
 	"golang.org/x/xerrors"
 
 	"github.com/scionproto/scion/go/lib/addr"
 	"github.com/scionproto/scion/go/lib/infra"
 	"github.com/scionproto/scion/go/lib/infra/modules/trust/v2/internal/decoded"
+	"github.com/scionproto/scion/go/lib/log"
 	"github.com/scionproto/scion/go/lib/scrypto"
 	"github.com/scionproto/scion/go/lib/scrypto/cert/v2"
 	"github.com/scionproto/scion/go/lib/scrypto/trc/v2"
@@ -91,9 +94,16 @@ func (p Provider) GetRawTRC(ctx context.Context, id TRCID, opts infra.TRCOpts) (
 	return raw, err
 }
 
-func (p Provider) getCheckedTRC(ctx context.Context, id TRCID,
+func (p Provider) getCheckedTRC(parentCtx context.Context, id TRCID,
 	opts infra.TRCOpts) (*trc.TRC, []byte, error) {
 
+	span, ctx := opentracing.StartSpanFromContext(parentCtx, "get_checked_trc")
+	defer span.Finish()
+	opentracingext.Component.Set(span, "trust")
+	span.SetTag("isd", id.ISD)
+	span.SetTag("version", id.Version)
+	logger := log.FromCtx(ctx)
+
 	decTRC, err := p.getTRC(ctx, id, opts)
 	if err != nil {
 		return nil, nil, serrors.WrapStr("unable to get requested TRC", err)
@@ -101,10 +111,12 @@ func (p Provider) getCheckedTRC(ctx context.Context, id TRCID,
 	if opts.AllowInactive {
 		return decTRC.TRC, decTRC.Raw, nil
 	}
+	logger.Trace("[TrustStore:Provider] Get latest TRC info", "isd", id.ISD)
 	info, err := p.DB.GetTRCInfo(ctx, TRCID{ISD: id.ISD, Version: scrypto.LatestVer})
 	if err != nil {
 		return nil, nil, serrors.WrapStr("unable to get latest TRC info", err)
 	}
+	logger.Trace("[TrustStore:Provider] Latest TRC info", "isd", id.ISD, "version", info.Version)
 	switch {
 	case info.Version > decTRC.TRC.Version+1:
 		return nil, nil, serrors.WrapStr("inactivated by latest TRC version", ErrInactive,
@@ -120,6 +132,8 @@ func (p Provider) getCheckedTRC(ctx context.Context, id TRCID,
 		// There might exist a more recent TRC that is not available locally
 		// yet. Fetch it if the latest version was requested and recursion
 		// is allowed.
+		logger.Debug("[TrustStore:Provider] Local latest TRC inactive, fetching from network",
+			"isd", id.ISD)
 		fetched, err := p.fetchTRC(ctx, TRCID{ISD: id.ISD, Version: scrypto.LatestVer}, opts)
 		if err != nil {
 			return nil, nil, serrors.WrapStr("unable to fetch latest TRC from network", err)
@@ -161,6 +175,7 @@ func (p Provider) getTRC(ctx context.Context, id TRCID, opts infra.TRCOpts) (dec
 func (p Provider) fetchTRC(ctx context.Context, id TRCID,
 	opts infra.TRCOpts) (decoded.TRC, error) {
 
+	logger := log.FromCtx(ctx)
 	server := opts.Server
 	if err := p.Recurser.AllowRecursion(opts.Client); err != nil {
 		return decoded.TRC{}, err
@@ -172,9 +187,13 @@ func (p Provider) fetchTRC(ctx context.Context, id TRCID,
 	// Choose remote server, if not set.
 	if server == nil {
 		var err error
+		logger.Debug("[TrustStore:Provider] Start choosing remote server for TRC resolution",
+			"isd", id.ISD, "addr", server)
 		if server, err = p.Router.ChooseServer(ctx, id.ISD); err != nil {
 			return decoded.TRC{}, serrors.WrapStr("unable to route TRC request", err)
 		}
+		logger.Debug("[TrustStore:Provider] Done choosing remote server for TRC resolution",
+			"isd", id.ISD, "addr", server)
 	}
 	decTRC, err := p.Resolver.TRC(ctx, req, server)
 	if err != nil {
@@ -207,9 +226,16 @@ func (p Provider) GetASKey(ctx context.Context, id ChainID,
 	return chain.AS.Keys[cert.SigningKey], nil
 }
 
-func (p Provider) getCheckedChain(ctx context.Context, id ChainID,
+func (p Provider) getCheckedChain(parentCtx context.Context, id ChainID,
 	opts infra.ChainOpts) (decoded.Chain, error) {
 
+	span, ctx := opentracing.StartSpanFromContext(parentCtx, "get_checked_chain")
+	defer span.Finish()
+	opentracingext.Component.Set(span, "trust")
+	span.SetTag("ia", id.IA)
+	span.SetTag("version", id.Version)
+	logger := log.FromCtx(ctx)
+
 	chain, err := p.getChain(ctx, id, opts)
 	if err != nil {
 		return decoded.Chain{}, serrors.WrapStr("unable to get requested certificate chain", err)
@@ -230,6 +256,8 @@ func (p Provider) getCheckedChain(ctx context.Context, id ChainID,
 	default:
 		// In case the latest certificate chain is requested, there might be a more
 		// recent and active one that is not locally available yet.
+		logger.Debug("[TrustStore:Provider] Local latest certificate chain inactive, "+
+			"fetching from network", "ia", id.IA)
 		fetched, err := p.fetchChain(ctx, id, opts)
 		if err != nil {
 			return decoded.Chain{},
@@ -307,6 +335,7 @@ func (p Provider) issuerActive(ctx context.Context, chain decoded.Chain,
 func (p Provider) fetchChain(ctx context.Context, id ChainID,
 	opts infra.ChainOpts) (decoded.Chain, error) {
 
+	logger := log.FromCtx(ctx)
 	server := opts.Server
 	if err := p.Recurser.AllowRecursion(opts.Client); err != nil {
 		return decoded.Chain{}, err
@@ -318,9 +347,13 @@ func (p Provider) fetchChain(ctx context.Context, id ChainID,
 	// Choose remote server, if not set.
 	if server == nil {
 		var err error
+		logger.Debug("[TrustStore:Provider] Start choosing remote server for certifcate chain "+
+			"resolution", "ia", id.IA)
 		if server, err = p.Router.ChooseServer(ctx, id.IA.I); err != nil {
 			return decoded.Chain{}, serrors.WrapStr("unable to route TRC request", err)
 		}
+		logger.Debug("[TrustStore:Provider] Done choosing remote server for certifcate chain "+
+			"resolution", "ia", id.IA, "addr", server)
 	}
 	chain, err := p.Resolver.Chain(ctx, req, server)
 	if err != nil {
diff --git a/go/lib/infra/modules/trust/v2/resolver.go b/go/lib/infra/modules/trust/v2/resolver.go
index fc6d1bc18..c35e79186 100644
--- a/go/lib/infra/modules/trust/v2/resolver.go
+++ b/go/lib/infra/modules/trust/v2/resolver.go
@@ -18,6 +18,8 @@ import (
 	"context"
 	"net"
 
+	"github.com/opentracing/opentracing-go"
+	opentracingext "github.com/opentracing/opentracing-go/ext"
 	"golang.org/x/xerrors"
 
 	"github.com/scionproto/scion/go/lib/infra/modules/trust/v2/internal/decoded"
@@ -55,15 +57,25 @@ type DefaultResolver struct {
 
 // TRC resolves the decoded signed TRC. Missing links in the TRC
 // verification chain are also requested.
-func (r DefaultResolver) TRC(ctx context.Context, req TRCReq,
+func (r DefaultResolver) TRC(parentCtx context.Context, req TRCReq,
 	server net.Addr) (decoded.TRC, error) {
 
+	span, ctx := opentracing.StartSpanFromContext(parentCtx, "resolve_trc")
+	defer span.Finish()
+	opentracingext.Component.Set(span, "trust")
+	span.SetTag("isd", req.ISD)
+	span.SetTag("version", req.Version)
+	logger := log.FromCtx(ctx)
+
 	if req.Version.IsLatest() {
+		logger.Debug("[TrustStore:Resolver] Resolving latest version of TRC", "isd", req.ISD)
 		latest, err := r.resolveLatestVersion(ctx, req, server)
 		if err != nil {
 			return decoded.TRC{}, serrors.WrapStr("unable to resolve latest version", err)
 		}
 		req = req.withVersion(latest)
+		logger.Debug("[TrustStore:Resolver] Resolved latest version of TRC",
+			"isd", req.ISD, "version", req.Version)
 	}
 	prev, err := r.DB.GetTRC(ctx, TRCID{ISD: req.ISD, Version: scrypto.LatestVer})
 	if err != nil && !xerrors.Is(err, ErrNotFound) {
@@ -99,6 +111,8 @@ func (r DefaultResolver) TRC(ctx context.Context, req TRCReq,
 			return decoded.TRC{}, serrors.WrapStr("unable to insert parts of TRC chain", err,
 				"trc", decTRC)
 		}
+		logger.Debug("[TrustStore:Resolver] Inserted resolved TRC", "isd", decTRC.TRC.ISD,
+			"version", decTRC.TRC.Version)
 		w.SetTRC(decTRC.TRC)
 	}
 	return decTRC, nil
@@ -123,17 +137,28 @@ func (r DefaultResolver) resolveLatestVersion(ctx context.Context, req TRCReq,
 	return decTRC.TRC.Version, nil
 }
 
-func (r DefaultResolver) startFetchTRC(ctx context.Context, res chan<- resOrErr,
+func (r DefaultResolver) startFetchTRC(parentCtx context.Context, res chan<- resOrErr,
 	req TRCReq, server net.Addr) {
 
 	go func() {
+		span, ctx := opentracing.StartSpanFromContext(parentCtx, "resolve_trc_link")
+		defer span.Finish()
+		opentracingext.Component.Set(span, "trust")
+		span.SetTag("isd", req.ISD)
+		span.SetTag("version", req.Version)
+		logger := log.FromCtx(ctx)
+
 		defer log.LogPanicAndExit()
+		logger.Debug("[TrustStore:Resolver] Fetch TRC from remote", "isd", req.ISD,
+			"version", req.Version, "server", server)
 		rawTRC, err := r.RPC.GetTRC(ctx, req, server)
 		if err != nil {
 			res <- resOrErr{Err: serrors.WrapStr("error requesting TRC", err,
 				"isd", req.ISD, "version", req.Version)}
 			return
 		}
+		logger.Debug("[TrustStore:Resolver] Received TRC from remote",
+			"isd", req.ISD, "version", req.Version)
 		decTRC, err := decoded.DecodeTRC(rawTRC)
 		if err != nil {
 			res <- resOrErr{Err: serrors.WrapStr("failed to parse TRC", err,
@@ -160,13 +185,24 @@ func (r DefaultResolver) trcCheck(req TRCReq, t *trc.TRC) error {
 
 // Chain resolves the raw signed certificate chain. If the issuing TRC is
 // missing, it is also requested.
-func (r DefaultResolver) Chain(ctx context.Context, req ChainReq,
+func (r DefaultResolver) Chain(parentCtx context.Context, req ChainReq,
 	server net.Addr) (decoded.Chain, error) {
 
+	span, ctx := opentracing.StartSpanFromContext(parentCtx, "resolve_chain")
+	defer span.Finish()
+	opentracingext.Component.Set(span, "trust")
+	span.SetTag("ia", req.IA)
+	span.SetTag("version", req.Version)
+	logger := log.FromCtx(ctx)
+
+	logger.Debug("[TrustStore:Resolver] Fetch certificate chain from remote", "ia", req.IA,
+		"version", req.Version, "server", server)
 	msg, err := r.RPC.GetCertChain(ctx, req, server)
 	if err != nil {
 		return decoded.Chain{}, serrors.WrapStr("error requesting certificate chain", err)
 	}
+	logger.Debug("[TrustStore:Resolver] Received certificate chain from remote", "ia", req.IA,
+		"version", req.Version)
 	dec, err := decoded.DecodeChain(msg)
 	if err != nil {
 		return decoded.Chain{}, serrors.WrapStr("error parsing certificate chain", err)
@@ -227,7 +263,6 @@ type resolveWrap struct {
 }
 
 func (w resolveWrap) TRC(ctx context.Context, id TRCID) (*trc.TRC, error) {
-
 	t, err := w.resolver.DB.GetTRC(ctx, id)
 	switch {
 	case err == nil:
diff --git a/go/lib/infra/modules/trust/v2/router.go b/go/lib/infra/modules/trust/v2/router.go
index 52a9fda89..9e060fa1c 100644
--- a/go/lib/infra/modules/trust/v2/router.go
+++ b/go/lib/infra/modules/trust/v2/router.go
@@ -22,6 +22,7 @@ import (
 	"golang.org/x/xerrors"
 
 	"github.com/scionproto/scion/go/lib/addr"
+	"github.com/scionproto/scion/go/lib/log"
 	"github.com/scionproto/scion/go/lib/scrypto"
 	"github.com/scionproto/scion/go/lib/serrors"
 	"github.com/scionproto/scion/go/lib/snet"
@@ -67,6 +68,8 @@ func (r AuthRouter) ChooseServer(ctx context.Context, subjectISD addr.ISD) (net.
 	if err != nil {
 		return nil, serrors.WrapStr("unable to determine dest ISD to query", err)
 	}
+	logger := log.FromCtx(ctx)
+	logger.Debug("[TrustStore:AuthRouter] Getting paths to any authoritative server", "isd", dstISD)
 	path, err := r.Router.Route(ctx, addr.IA{I: dstISD})
 	if err != nil {
 		return nil, serrors.WrapStr("unable to find path to any core AS", err, "isd", dstISD)
diff --git a/go/lib/log/BUILD.bazel b/go/lib/log/BUILD.bazel
index c16f6c7be..91a3ade81 100644
--- a/go/lib/log/BUILD.bazel
+++ b/go/lib/log/BUILD.bazel
@@ -6,6 +6,7 @@ go_library(
         "context.go",
         "flags.go",
         "log.go",
+        "span.go",
         "syncbuf.go",
         "wrappers.go",
     ],
@@ -19,6 +20,7 @@ go_library(
         #"@com_github_inconshreveable_log15_ext//:go_default_library",
         "@com_github_kormat_fmt15//:go_default_library",
         "@com_github_mattn_go_isatty//:go_default_library",
+        "@com_github_opentracing_opentracing_go//:go_default_library",
         "@in_gopkg_natefinch_lumberjack_v2//:go_default_library",
     ],
 )
diff --git a/go/lib/log/context.go b/go/lib/log/context.go
index 66c691f83..c7b7dc0c4 100644
--- a/go/lib/log/context.go
+++ b/go/lib/log/context.go
@@ -17,6 +17,8 @@ package log
 
 import (
 	"context"
+
+	"github.com/opentracing/opentracing-go"
 )
 
 type loggerContextKey string
@@ -37,11 +39,21 @@ func FromCtx(ctx context.Context) Logger {
 		return Root()
 	}
 	if logger := ctx.Value(loggerKey); logger != nil {
-		return logger.(Logger)
+		return attachSpan(ctx, logger.(Logger))
 	}
 	// Logger not found in ctx, make sure we never return a nil root
 	if Root() == nil {
 		panic("unable to find non-nil logger")
 	}
-	return Root()
+	return attachSpan(ctx, Root())
+}
+
+func attachSpan(ctx context.Context, logger Logger) Logger {
+	if span := opentracing.SpanFromContext(ctx); span != nil {
+		return Span{
+			Logger: logger,
+			Span:   span,
+		}
+	}
+	return logger
 }
diff --git a/go/lib/log/span.go b/go/lib/log/span.go
new file mode 100644
index 000000000..04728e94e
--- /dev/null
+++ b/go/lib/log/span.go
@@ -0,0 +1,68 @@
+// Copyright 2019 Anapaya Systems
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package log
+
+import (
+	"github.com/opentracing/opentracing-go"
+)
+
+// Span is a logger that attaches all logs to the span.
+type Span struct {
+	Logger
+	Span opentracing.Span
+}
+
+// Trace logs to the logger and span.
+func (s Span) Trace(msg string, ctx ...interface{}) {
+	s.Logger.Debug(TraceMsgPrefix+msg, ctx...)
+	s.spanLog("trace", msg, ctx...)
+}
+
+// Debug logs to the logger and span.
+func (s Span) Debug(msg string, ctx ...interface{}) {
+	s.Logger.Debug(msg, ctx...)
+	s.spanLog("debug", msg, ctx...)
+}
+
+// Info logs to the logger and span.
+func (s Span) Info(msg string, ctx ...interface{}) {
+	s.Logger.Info(msg, ctx...)
+	s.spanLog("info", msg, ctx...)
+}
+
+// Warn logs to the logger and span.
+func (s Span) Warn(msg string, ctx ...interface{}) {
+	s.Logger.Warn(msg, ctx...)
+	s.spanLog("warn", msg, ctx...)
+}
+
+// Error logs to the logger and span.
+func (s Span) Error(msg string, ctx ...interface{}) {
+	s.Logger.Error(msg, ctx...)
+	s.spanLog("error", msg, ctx...)
+}
+
+// Crit logs to the logger and span.
+func (s Span) Crit(msg string, ctx ...interface{}) {
+	s.Logger.Crit(msg, ctx...)
+	s.spanLog("crit", msg, ctx...)
+}
+
+func (s Span) spanLog(lvl, msg string, ctx ...interface{}) {
+	if s.Span == nil {
+		return
+	}
+	s.Span.LogKV(append([]interface{}{"level", lvl, "event", msg}, ctx...)...)
+}
diff --git a/go/lib/sciond/BUILD.bazel b/go/lib/sciond/BUILD.bazel
index 82a241a1f..f2e2ce510 100644
--- a/go/lib/sciond/BUILD.bazel
+++ b/go/lib/sciond/BUILD.bazel
@@ -22,6 +22,7 @@ go_library(
         "//go/lib/snet:go_default_library",
         "//go/lib/sock/reliable:go_default_library",
         "//go/lib/spath:go_default_library",
+        "//go/lib/tracing:go_default_library",
         "//go/lib/util:go_default_library",
         "//go/proto:go_default_library",
     ],
diff --git a/go/lib/sciond/sciond.go b/go/lib/sciond/sciond.go
index 718277c8d..0f8c19cd1 100644
--- a/go/lib/sciond/sciond.go
+++ b/go/lib/sciond/sciond.go
@@ -41,6 +41,7 @@ import (
 	"github.com/scionproto/scion/go/lib/serrors"
 	"github.com/scionproto/scion/go/lib/snet"
 	"github.com/scionproto/scion/go/lib/sock/reliable"
+	"github.com/scionproto/scion/go/lib/tracing"
 	"github.com/scionproto/scion/go/proto"
 )
 
@@ -172,7 +173,8 @@ func (c *conn) Paths(ctx context.Context, dst, src addr.IA, max uint16,
 	reply, err := roundTripper.Request(
 		ctx,
 		&Pld{
-			Which: proto.SCIONDMsg_Which_pathReq,
+			TraceId: tracing.IDFromCtx(ctx),
+			Which:   proto.SCIONDMsg_Which_pathReq,
 			PathReq: &PathReq{
 				Dst:      dst.IAInt(),
 				Src:      src.IAInt(),
@@ -200,7 +202,8 @@ func (c *conn) ASInfo(ctx context.Context, ia addr.IA) (*ASInfoReply, error) {
 	pld, err := roundTripper.Request(
 		ctx,
 		&Pld{
-			Which: proto.SCIONDMsg_Which_asInfoReq,
+			TraceId: tracing.IDFromCtx(ctx),
+			Which:   proto.SCIONDMsg_Which_asInfoReq,
 			AsInfoReq: &ASInfoReq{
 				Isdas: ia.IAInt(),
 			},
@@ -227,7 +230,8 @@ func (c *conn) IFInfo(ctx context.Context,
 	pld, err := roundTripper.Request(
 		ctx,
 		&Pld{
-			Which: proto.SCIONDMsg_Which_ifInfoRequest,
+			TraceId: tracing.IDFromCtx(ctx),
+			Which:   proto.SCIONDMsg_Which_ifInfoRequest,
 			IfInfoRequest: &IFInfoRequest{
 				IfIDs: ifs,
 			},
@@ -254,7 +258,8 @@ func (c *conn) SVCInfo(ctx context.Context,
 	pld, err := roundTripper.Request(
 		ctx,
 		&Pld{
-			Which: proto.SCIONDMsg_Which_serviceInfoRequest,
+			TraceId: tracing.IDFromCtx(ctx),
+			Which:   proto.SCIONDMsg_Which_serviceInfoRequest,
 			ServiceInfoRequest: &ServiceInfoRequest{
 				ServiceTypes: svcTypes,
 			},
@@ -290,7 +295,8 @@ func (c *conn) RevNotification(ctx context.Context,
 	reply, err := roundTripper.Request(
 		ctx,
 		&Pld{
-			Which: proto.SCIONDMsg_Which_revNotification,
+			TraceId: tracing.IDFromCtx(ctx),
+			Which:   proto.SCIONDMsg_Which_revNotification,
 			RevNotification: &RevNotification{
 				SRevInfo: sRevInfo,
 			},
diff --git a/go/lib/sciond/types.go b/go/lib/sciond/types.go
index cbb198b85..e0f7eb05c 100644
--- a/go/lib/sciond/types.go
+++ b/go/lib/sciond/types.go
@@ -62,6 +62,7 @@ var _ proto.Cerealizable = (*Pld)(nil)
 
 type Pld struct {
 	Id                 uint64
+	TraceId            []byte
 	Which              proto.SCIONDMsg_Which
 	PathReq            *PathReq
 	PathReply          *PathReply
diff --git a/go/lib/scrypto/version.go b/go/lib/scrypto/version.go
index 0ccb6e622..2a051ac71 100644
--- a/go/lib/scrypto/version.go
+++ b/go/lib/scrypto/version.go
@@ -39,6 +39,13 @@ func (v Version) IsLatest() bool {
 	return v == LatestVer
 }
 
+func (v Version) String() string {
+	if v.IsLatest() {
+		return "latest"
+	}
+	return strconv.FormatUint(uint64(v), 10)
+}
+
 // UnmarshalJSON checks that the value is not LatestVer.
 func (v *Version) UnmarshalJSON(b []byte) error {
 	parsed, err := strconv.ParseUint(string(b), 10, 64)
diff --git a/go/lib/tracing/context.go b/go/lib/tracing/context.go
index 2964437c5..bb540720a 100644
--- a/go/lib/tracing/context.go
+++ b/go/lib/tracing/context.go
@@ -15,6 +15,7 @@
 package tracing
 
 import (
+	"bytes"
 	"context"
 
 	"github.com/opentracing/opentracing-go"
@@ -26,16 +27,29 @@ import (
 
 // CtxWith creates a new span and attaches it to the context, it also sets the
 // debug id of the logger and the span id and attaches the logger to the context.
-func CtxWith(parentCtx context.Context, parentLogger log.Logger, operationName string,
-	opts ...opentracing.StartSpanOption) (context.Context, opentracing.Span) {
+func CtxWith(parentCtx context.Context, operationName string,
+	opts ...opentracing.StartSpanOption) (opentracing.Span, context.Context) {
 
-	debugId := util.GetDebugID()
 	span, ctx := opentracing.StartSpanFromContext(parentCtx, operationName, opts...)
 	if spanCtx, ok := span.Context().(jaeger.SpanContext); ok {
-		ctx = log.CtxWith(ctx, parentLogger.New("debug_id", debugId, "trace_id", spanCtx.TraceID()))
-		span.SetTag("LogDebugId", debugId)
-	} else {
-		ctx = log.CtxWith(ctx, parentLogger.New("debug_id", util.GetDebugID()))
+		id := spanCtx.TraceID()
+		return span, log.CtxWith(ctx, log.New("debug_id", id.String()[:8], "trace_id", id))
 	}
-	return ctx, span
+	return span, log.CtxWith(ctx, log.New("debug_id", util.GetDebugID()))
+}
+
+// IDFromCtx reads the tracing ID from the context.
+func IDFromCtx(ctx context.Context) []byte {
+	span := opentracing.SpanFromContext(ctx)
+	if span == nil {
+		return nil
+	}
+	var tracingBin bytes.Buffer
+	err := opentracing.GlobalTracer().Inject(span.Context(), opentracing.Binary, &tracingBin)
+	if err != nil {
+		// According to the opentracing documentation, this error should never happen:
+		// "All opentracing.Tracer implementations MUST support all BuiltinFormats."
+		panic(err)
+	}
+	return tracingBin.Bytes()
 }
diff --git a/go/proto/sciond.capnp.go b/go/proto/sciond.capnp.go
index 3c18142e3..950ef9370 100644
--- a/go/proto/sciond.capnp.go
+++ b/go/proto/sciond.capnp.go
@@ -66,12 +66,12 @@ func (w SCIONDMsg_Which) String() string {
 const SCIONDMsg_TypeID = 0x91ea9bb47f46c346
 
 func NewSCIONDMsg(s *capnp.Segment) (SCIONDMsg, error) {
-	st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 16, PointerCount: 1})
+	st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 16, PointerCount: 2})
 	return SCIONDMsg{st}, err
 }
 
 func NewRootSCIONDMsg(s *capnp.Segment) (SCIONDMsg, error) {
-	st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 16, PointerCount: 1})
+	st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 16, PointerCount: 2})
 	return SCIONDMsg{st}, err
 }
 
@@ -497,12 +497,26 @@ func (s SCIONDMsg) NewSegTypeHopReply() (SegTypeHopReply, error) {
 	return ss, err
 }
 
+func (s SCIONDMsg) TraceId() ([]byte, error) {
+	p, err := s.Struct.Ptr(1)
+	return []byte(p.Data()), err
+}
+
+func (s SCIONDMsg) HasTraceId() bool {
+	p, err := s.Struct.Ptr(1)
+	return p.IsValid() || err != nil
+}
+
+func (s SCIONDMsg) SetTraceId(v []byte) error {
+	return s.Struct.SetData(1, v)
+}
+
 // SCIONDMsg_List is a list of SCIONDMsg.
 type SCIONDMsg_List struct{ capnp.List }
 
 // NewSCIONDMsg creates a new list of SCIONDMsg.
 func NewSCIONDMsg_List(s *capnp.Segment, sz int32) (SCIONDMsg_List, error) {
-	l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 16, PointerCount: 1}, sz)
+	l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 16, PointerCount: 2}, sz)
 	return SCIONDMsg_List{l}, err
 }
 
@@ -2248,129 +2262,131 @@ func (p SegTypeHopReplyEntry_Promise) Struct() (SegTypeHopReplyEntry, error) {
 	return SegTypeHopReplyEntry{s}, err
 }
 
-const schema_8f4bd412642c9517 = "x\xda\x94W}l[\xd5\x15?\xe7^\xbb\xb6\x13;" +
-	"\xb6\xfb\x1c\xa82m\x19UQ\x9b\x8aT$\xd0\xad\xaa" +
-	"4\xd2\xa6M\x88\xd9\x02yv6\x09\x04\x1a&~N" +
-	"<9\xb6\xfb\xdeK\x1a#\xba\xd0)\xd9X\x07\xa2\x08" +
-	"\xaa}\xb4h|\xac]\xb3\x81F\xbb\x16A\xa7!!" +
-	"\x9aM\x8b`\x03\x89\x89-*\x03:J\x9b\xb2iK" +
-	"iW\xd2\xad{\xd3y\xdf}}),\x7f]\xe7w" +
-	"|\xee\xf9\xfa\xfd\xce\xf5\xf5<\xb8\x81\xb5\x05\xff\x11\x02" +
-	"\x10\xef\x0c.\xd1>z\xee\xd9}\x1f\x9e\xbd\xf7;\x90" +
-	"\x8c\xa1v\xf5\xae\xeb\xf2K\xdf\xfc\xf2\xc3\x10\xc4\x10\x80" +
-	"\xf06\x9f\x15\xe68\x9dN\xf0\x0e@\xed\xec\xec\xc2\xd7" +
-	"_\x9ayg\x07\x881t\x1b32i\x0c\xcc\x08\xd7" +
-	"\x04\xe8\xf4\xd9\xc0I@\xad)\xb9\xa7\xfb}y\xfb\xc3" +
-	"\x1ec\xdd\"\x18<(\xc4\x82t\x8a\x04\xc9q\xf7+" +
-	"\xdd\xe3\x87v\x9f~\x84l\x99c\xdb\x85\xa1\x18\x06\x84" +
-	"\x96\xe0\x11\xa1\x8d\xacoh\x0d^\xcd\x01\xb5\xc7O\xa5" +
-	"\x8e\xafZ\xf6\xcd\xc7\xfcb~(<#\xfc0L\xa7" +
-	"]ar\xfd\xe4\xb6\xfa\xfdk7\xd4vy\\\xeba" +
-	"L\x87g\x857t\xdb\xd7\xc2[\x01\xb5\xb9\xcew&" +
-	"\x7f:\xb9d\xb7\x9f\xdf\x96\xc8iam\x84Nm\x11" +
-	"\xf2;\xfb\xe7\x1d\xa7\xde\x0b\xfe~7\x88\x8d\xc8\xb5\x0f" +
-	"\x9f>z\xac\xad\xf17G\xa1\x11C\x08 |52" +
-	"\x0b(\xdc\x1e!\xafK\xdb\x9eh\xbb3|\xdb\x94\x8f" +
-	"\xd7\x1b\x0eG\x18\x0a/\xebn\x7f\xad\xbb=4?%" +
-	"\xde\xb1\xec\xe3g\xbc%\xd6\xad\xe7#KQ\xc0:\xb2" +
-	"\xbe\x18\xf9\x05\xa0\xf6\xf9k\x1f\xdd\x1a\\\xd9t\xd0\xb7" +
-	"!\xcf\xd6\x1d\x14\x0e\xeb\xc6\x07\xea(\x8eSg\xae\x1a" +
-	"=\xf1\xf7\x0d\xaf\xf8e7_wZ\xb8\xa8\xdb.\xd4" +
-	"Q\x18v>b\x0c\xf9e\xa5\xa8\xff\x99\xd0V\xaf\xf7" +
-	"\xa3\xbe\x19\x01\xb5\xbf\x8d~\xbf\xda\xbfF\x9b\xf6x\xd6" +
-	"\xa3X\x1b=.l\x8c\xd2\xe9KQ\x8a\".\xfda" +
-	"c\xe7\xc4\xe7f\xfc\xc6\xe2\xf1\xe8\xac0\xa5\xdb\xee\x8d" +
-	"R\x14{?X\xb1g\xffS\xd2\xab~\xb6\xd3\xd1#" +
-	"\xc2k\xba\xed\xeft\xdbc\xef\xfdj\xdfw\x1f]y" +
-	"\xd2\xb7ps\xd1&\x14\x16t\xebsQ*\\\xe9\xdd" +
-	"\xcc\xd7\x9a\xde8\x7f\xd2\xaf\x16{c3\xc2\x81\x98^" +
-	"\xc1\x18y^\xb7\xf2\xado\x0f6N\xff\xd3\xcf\xb3\xf0" +
-	"v\xec\x8c0\xa7\x1b\x9f\x88Qz\x1d\x1f\xdc\xd4\xf2\xfc" +
-	"\\|\xde\xd7\xb8\xab\xe1\x88\xd0\xdb@\xa7t\x03\x19\xbf" +
-	"\xf8\xd2\xd8\xd4\xf7\xde\xdaw\xde/\x8a\x17\x1b\xce\x08\xd3" +
-	"\xba\xed\xcb\x0d\x14E\xb4\xe9/?\x1f\xbc\xf6\xc4\x02\x88" +
-	"W\xa1\xab\xf1\x8dL\x9f\xb7\xf9\x86\xe3\x80\xc29\xdd\xeb" +
-	"/\x9f\xbf\xf7\xe6CO\x1f\xb8\xe07\xf1b\xfc\x8cp" +
-	"W\x9cN\xb7\xc7\xa9\x0e\xca@\xb1R\xce\xaf\x19`\xb9" +
-	"j\xb9\xba>\xdd\x9d.\x17*\x19i\xcb\x88\xc4\x15\xb5" +
-	"\x0fQ\x0c\xf0\x00@\x00\x01\x92\xb1v\x001\xccQ\\" +
-	"\xc1\xb0\xb9XHoV\xb0\x01\xb0\x8f#F\x80\xd1\xd1" +
-	"\xe3\xab{k\xbe/\xa7\x0e\xf5Jj\x0e\x80\\%l" +
-	"W\xb9N\xd2\x1e\x8e\xe2\x10C\xc4\x14\xd2\xff\xa4\xe5\x00" +
-	"\xe2\xdd\x1c\xc5\x12\xc3$\xc3\x142\x80d\xf1\x0e\x00q" +
-	"\x88\xa38\xc10\xc91\x85\x1c \xb9\x9d\xbe}\x1fG" +
-	"\xf1\x01\x86\xe3\x05\xe3\x16\x8c\x01\xc3\x18`hX\x1d\xc1" +
-	"\x100\x0c\x01j\xc5\xb2*\xc9\x85\xdc\x00p\xc9\x8e5" +
-	"\xe1\xe8\x01 \xfds\\\x1a\xab\xf6\x17\x87%\x0c\x03\xc3" +
-	"\xb0+\x0b\xd4\xb3\xc8H\xa3\xcd\x19\xa9Z\xaay\x8a\xb1" +
-	"\xde,F\x8aa\x87,)#%\xd5\xbe\xf6R\x07\xd9" +
-	"M\xe9\x8e\xdbn\xdd\xdc\xab\x0c\x92\x87u\x96\x07\xa1\x86" +
-	"M\x00Y\x159f\xefG\x861\xd44\xbd\x10\xc26" +
-	"l\x07\xc8\x8e\x110A\x00\xfb\xaf\xa6\x17C\xd8\x8e\x9d" +
-	"\x00\xd9\xfb\x08x\x80\x00~Q\xd3\x0b\"Lb\x06 " +
-	";A\xc0N\x02\x02\xff\xd1R\x18 )\xd4\x81\x07\x09" +
-	"\xf8\x01\x01\xc1\x7fk)\x0c\x922\xe2=\x00\xd9\xc7\x08" +
-	"x\x82\x80%\x17\xb4\x14.!\x02\xe2\xb7\x00\xb2{\x08" +
-	"\xd8O@hAK\x19\x9c@\x19 \xfb\x13\x02\x9e#" +
-	" \xfc\xb1\x96\xc20QDw\xf5\x0c\x01/\x10\x109" +
-	"\xaf\xa50\x02 \x1c\xc6\x1f\x01d_ \xe0(\x01u" +
-	"\xff\xd2RXG\xe3\x8c;\x00\xb2G\x09x\x9d\x80\xfa" +
-	"sZ\x0a\xebI\x83\xf1\x16\x80\xec\xab\x04\xfc\x89\x80\xe8" +
-	"Y-\x85Q\x00\xe1\x8f\xfa\xe5o\x12\xf0.\x01\xb1\x8f" +
-	"\xb4\x14\xc6\x88|z\xb8\xc7\x088\x85\x0cy1\xaf\x0f" +
-	"c\x04\xb0y\xa4\xacH*,\x19\xaf\xe6\xd4\xa1\x8c\xb4" +
-	"\x05\x13\x8e\xa4\x01b\x02P3\x90j\x09\xb0\x86\x09\x87" +
-	"\xb7&\x9aS\x0c*\x00\xd2wm!\xf2\xa2\xa1j\x89" +
-	"\xbem/$\x13\x97\xa5\xd1[+j\xb1\x80\xc5\x81\x9c" +
-	"Z\xac\x94\x01\x13\xcer1m\x8a\x05\xd3G\xf3\x96\x11" +
-	"IQ1\xe1\xacb\xaf\x85y\x8b-Z&\xaeH\xf2" +
-	"hq@J\xa3\x8b\xb4\x98p\xf6\x8d\xafY\xb5T\x03" +
-	"\x0a\xc7\xd6\x1e'd\x13$\xd4^\xde\xb6\x8f\xc1\xfeZ" +
-	"U\xea\x81\xe6J\xd5(\xa7\xad\xe3\x1e\x0b$\x03\xf2\x83" +
-	"\x09g\xe3X6\x97(\xc4\xc6l\xda\x89\xc8\xc3\xafN" +
-	"Gl\xc6\xa5\xb2*\x17\xdd\x14\xb6\x05\xce\xa0\xb0\xc7-" +
-	"\xe9A\xda\xa0>\x1f\x90\xc8o\xd8\xf6\xdbB\"\xb6\x82" +
-	"\xa3x=\xc3\xa4%=\xad\xab\x01\xc4U\x1c\xc5\x1bI" +
-	"\xd9\x94|N\xb1\xa6(N:g}\xf0\\\x931[" +
-	"\\\x1c\xc8\xc5\xa9\xc5\x9e\x04n\x01\x10\xa3\x1c\xc5e\x0c" +
-	"5%#\x8dR\xaaFi3\x7f\xbd\xf0\xc5\xc9\x9b\xdb" +
-	"\x7f\xec_\x94>c^\xd7\x14J9>\xa8P\xe8\x89" +
-	"\x9d\x86\xee\xb5t\xbac\x7fD\xa7x\xb2u\xbd\x13\xfb" +
-	"\xb8,\x15dI\x19B\x04\x86\x08\xd81T\xcc\xe7\xa5" +
-	"\xb2\xf5\xd1\xbe\x88\x1b\xc2dN\x855;\x8a\xea\xed\xc1" +
-	"7\xcc\x14V1{\x86\xfa!^\xab:\xad\x88k\xea" +
-	"\xe0\xeb\x9fii\xcd\x1c\xf7\xb6\xc2\xba\xc3\x98\x09s$" +
-	"\xba\xca\xaa\x8c\xba\x92F\xed[\xbaH\xe27s\x14\xef" +
-	"vv\xc1]\x19g?\xd8\xbb@\xeat\x16\xc4\xa7\x93" +
-	"vM-\x0eK\x8a\x9a\x1b\x06\xacZ\xf2\xfe\x09r\xdf" +
-	"SQ\x9aU*\x89glV;\xa5\xa7?g\x19'" +
-	"[\xdb\x81\xc5\xab\x15\xd9\xd6\xff\xe6\\>/+\x9e\xae" +
-	"\xba\x0a\x11\xf7\xd9&W\x9cv\xfbE\xe8)1Z\xf3" +
-	"\x12\xa7\x81!\x8f)\xdb\xe36\xda\xa6c\xe6\xe2\xb4\xca" +
-	"\xba}\xb9\xb38\x93,l\x94u\x92\x06u\x82\xa3\xb8" +
-	"\x93!rt\xbdk\x93\x0f\xb5\x03\xc3\x80\xbe1\x92#" +
-	"4gU\x8e\xe2\x83\x0cCyE\xb5H\x11R\xe4\x01" +
-	"\x9b \xc3\xb91\x1a_\x85\xe6\xdc\xaaF\xa1\x94\x1bT" +
-	":\x86\xaa\x9b\x0a\x83\xae\x9c\x96u\xbd\x7f\x93\xf0\xdbk" +
-	"\x8e,\xce`s`B\xaa\\[\xbc\x17\x0e\x85)\x8b" +
-	"\xeb8\x8a\xeb\x18\xc6I\xd81\xe1\xfcX1y6T" +
-	"QT\x87\x85\xf6\x03\xca\x97\x85\xae~q\xa3\xb6\xaen" +
-	"\xadvv\x7f\\\xadU%\x8ck\xf7\xaf{\xaaN\x9a" +
-	":\xff$y\x8b_\xd6\xa3\x8d\xd9t\x87A\xb3E\x9e" +
-	"T)\xaf\xf0\\\x89\xab\x06\x91\xb8\xec%\xd2=&\x91" +
-	"\xfa\\u\xe9\xa5\x96\xf7p\x14\xfb\x19\"3:.\x12" +
-	"\xbb\xfaL\"\xd9\xbc\x0e\x19\x89\xb8\xf9\x1c\x07\x0c\xa9j" +
-	"\xc9\xa6\x8a]@tu\xd2]\xc7\x86E\x1f\x94\xff\xb7" +
-	"\xc4\xdbo\xeeOr\xdbL\xa2R\xbb\x12]}&\xe4" +
-	"\x12Y\xfftsa\xb3\xadc\xc8~\x0f\xban\xcc8" +
-	"2l\xdd\xd8\xd6i\xde\xd8\xc3P\x93d\xb9\"o\xaa" +
-	"\xe4\x01%\x8b\x1a\x97'm\xff\x8c\xf2M\xda5\x04\xbe" +
-	"O\xd2+\xd6\xd3\xfeu\xe4\xeb\xba\xc7,\xc1\x9a\\>" +
-	"\x94\x97\x15#1#\x8b\xcb\xe8\xc6<\x1b3^\xac\x8e" +
-	"\xdeh\xbd\xbf\xe9\xc3\x17\xac\x0f\x8b\xaf{\xa7i\xae\xf9" +
-	"%2l\xe0(~\x85.\x0a\x18\xb7\xa7\x97\xbb\x86\x9a" +
-	"\xf5\x19\xb7\xf7\xaew\x86\xfaR\xda\xb8\x9f\xff\x1dEe" +
-	"SE\x96\xac\xed\xf7\xbf\x00\x00\x00\xff\xffvu8\x1b"
+const schema_8f4bd412642c9517 = "x\xda\x94W}l\x1bg\x19\x7f\x9e\xf7\xec\xd8Nl" +
+	"\x9f\xddsF\x09\x82\xd0\xaaU\x9bj\xa9\x96t\x85\xae" +
+	"\x82\xa5M\xdb,\x1et\xcd\xd9\x11\x7fLC\xcc\x8b_" +
+	"'FN\xec\xdc]\xd2z\xa2\x84\xa2\x06XaZ\xab" +
+	"-\x82\xd1N\xb4\x1b\x94\x06\x86\xd8J5\xb1\x82&\xd0" +
+	":>\xa2\x09\x98T4-\x1a\xac-\xeb\xdat\xabX" +
+	"\xba\x8e~\xd0r\xe8\xb9;\xdf]/\xd7\x8f\xe5\xaf7" +
+	"\xfe=\xfe\xbd\xcf\xd7\xefy^\xdf1/\xb8\x86\xb5\x05" +
+	"\xff\x1d\x02\x90\x1f\x08\xd6\xe9\x1f<\xf7\x8b\xfd\xef\x9e\x7f" +
+	"\xf8\xdb\x90\x8c\xa1\xfe\xb1\x89\xdb\xf3\xf3\x8e~\xe11\x08" +
+	"b\x08@\xfa\x870-\xcd\x08t:)t\x00\xea\xe7" +
+	"\xa7/}\xe5\xa5\xa9\xb7v\x80\x1cC\xb71#\x93\xc6" +
+	"\xc0\x94\xb4 @\xa7O\x06N\x01\xeaM\xc9=]o" +
+	"+\xdb\x1e\xf3\x18\x1b\x16\xc1\xe0A)\x16\xa4S$H" +
+	"\xc4]/w\x8d\x1d\xda}f\x17\xd92\xc7v\x03\x0b" +
+	"\xc50 \xb5\x04\x0fKmd\xbd\xa25\xb8I\x00\xd4" +
+	"\x9f:\x9d:\xb1t\xfe\xd7\x9f\xf0\xf3\xf9\xcf\xe1)\xe9" +
+	"\xefa:\xbd\x16&\xea}[\x1b\x0e\xac\\S\x9d\xf0" +
+	"P\x1bn`dZ\x8aE\x0c7\"\x9b\x01\xf5\x99\xce" +
+	"\xb7\xc6\x7f:^\xb7\xdb\x8f\x97G\xceH\xc3\x86\xed`" +
+	"\x84x\xa7\xdf\xd8q\xfax\xf0/\xbbAnDA\x7f" +
+	"\xf7\x99#o\xb65\xfe\xe1\x084b\x08\x01\xa4]\x91" +
+	"i@i\xc2`\x9d\xd7\xb6\xb7\xed\x81\xf0\xa6I\x1f\xd6" +
+	"\x15\xb3\x11\x86\xd2U\x83\xf6\x92A{hvR\xbe\x7f" +
+	"\xfe\xc5g\xbd)6\xac[\xeb\xe7\xa1\xf4\xf9z\xb2\xbe" +
+	"\xab\xfe\x97\x80\xfa\xa7\x17?\xbe9\xb8\xa4\xe9\xa0oA" +
+	"f\xea\x0fJ\xb3\x86\xf1\xd9z\xf2\xe3\xf4\xb9\xdbFO" +
+	"\x9e]\xf3\xb2_t\xad\x0dg\xa4\xbb\x1a\xe8\xb4\xb2\x81" +
+	"\xdc\xb0\xe3\x91c(\xccIE\xc3\xcf\xa4A2^Q" +
+	"lhF@\xfd\xbd\xd1\xefWz\x97\xeb\xafx\x98\x0d" +
+	"/\x86\xa3'\xa4\xadQ:U\xa3\xe4\x85\xc8\xff\xba\xb6" +
+	"s\xfb\xa7\xa6\xfc\xda\xe2\x8d\xe8\xb4t\xd2\xb0=\x1e%" +
+	"/~\xf2\xce\xa2=\x07\x9e\xe6\xaf\xfa\xd9b\xec\xb0\x14" +
+	"\x89\x19\xcd\x14#\xdb7\x8f\xfff\xff#\x8f/9\xe5" +
+	"\x9b\xb8\xc5\xb1&\x94V\x1a\xd6m1J\\\xe9X\xe6" +
+	"KM\xaf]8\xe5\x97\x8b\xe3\xb1)\xe9\xaca;c" +
+	"0\xafZ\xf2\xfa\xb7\xfa\x1b_y\xdf\x8fY\xfax\xfc" +
+	"\x9c\xb48N\xa7\x05q\x0a\xaf\xe3\x9d\xbb[^\x98\x11" +
+	"g}\x8d\xb7\xc5\x0fK\x8f\x18\xc6\xe3\x86\xf1\x8b/m" +
+	"\x99\xfc\xee\xeb\xfb/\xf8y\xf1a\xfc\x9c\x84\"\x9d\xae" +
+	"\xc6\xc9\x8bh\xd3?\x7f\xde\xbf\xf8\xe4%\x90oCW" +
+	"\xe1\x1b\x99\xd1o\xad\xe2\x09@\xa9M$\xd6_\xbd\xf0" +
+	"\xf0=\x87\x9ey\xfe\xb2_\xc7?*\x9e\x93\x9e4X" +
+	"'D\xca\x83\xdaW,\x0f\xe5\x97\xf7\xb1\\e\xa8\xb2" +
+	":\xdd\x95\x1e*\x943|x\x84\x0b\xaa\xd6\x83(\x07" +
+	"\x84\x00@\x00\x01\x92\xb1v\x009,\xa0\xbc\x88as" +
+	"\xb1\x90^\xafb\x1c\xb0G@\x8c\x00\xa3\xa3\x87\xabk" +
+	"s\xbe'\xa7\x0dl\xe4Z\x0e\x80\xa8\x126U\xae\x93" +
+	"f\x8f\x80\xf2\x00C\xc4\x14\xd2g|!\x80\xfc\xa0\x80" +
+	"r\x89a\x92a\x0a\x19@\xb2x?\x80< \xa0\xbc" +
+	"\x9daR\xc0\x14\x0a\x00\xc9m\xf4\xed\xaf\x09(\x7f\x87" +
+	"\xe1X\xc1\xbc\x05c\xc00\x06\x18\x1a\xd4F0\x04\x0c" +
+	"C\x80zqH\xe3J!\xd7\x07\x02\xb7}M8\xf3" +
+	"\x00\x90>\x1c\xe3[*\xbd\xc5A\x8ea`\x18vE" +
+	"\x81F\x14\x19>\xda\x9c\xe1\x95R\xd5\x93\x8c\xd5V2" +
+	"R\x0c;\x14\xae\x8e\x944\xfb\xdak\x09\xb2\xeb\xd2\x1d" +
+	"\x9b\xee[\xbfQ\xed'\x86\xcf\xd5\x18\xa4\x09l\x02\xc8" +
+	"\xeeD\x01\xb3{\x90a\x0cu\xddH\x84\xf4$\xb6\x03" +
+	"d\x9f `/\x01\xec\x7f\xba\x91\x0c\xe9)\xec\x04\xc8" +
+	"\xfe\x80\x80\x1f\x13 \\\xd5\x8d\x84H\xfb0\x03\x90\xdd" +
+	"K\xc0\xb3\x04\x04\xae\xe8)\x0c\x00H\x93\x06p\x80\x80" +
+	"C\x04\x04\xff\xab\xa70\x08 =\x8f\x0f\x01d\x9f#" +
+	"\xe0\xb7\x04\xd4]\xd6SX\x07 \xbd\x88\xdf\x04\xc8\xfe" +
+	"\x9a\x80#\x04\x84.\xe9)\xa3\x1b\x7f\x8f\x0a@\xf6w" +
+	"\x04\xbcJ@\xf8\xa2\x9e\xc20\x8d[\x83\xeaO\x04\x1c" +
+	"% rAOa\x84\xa6/\xfe\x10 {\x94\x80c" +
+	"\x04\xd4\xffGOa=-\x15\xdc\x01\x90=F\xc0{" +
+	"\x044|\xa8\xa7\xb0\x81\xd4\x86\xf7\x02dO\x13p\x9e" +
+	"\x80\xe8y=\x85Q\x00i\xd6\xb8\xfc}\x02\xae\x10\x10" +
+	"\xfb@Oa\x8cF\xa6\xe1\xeeE\x02\x02\x8ca2\x8e" +
+	")\x8c\xd3l`\x94\xaa+\xf4y\x981\x14\x8ay\xa3" +
+	"I#\x80\xcd#C*\xd7\xa0n\xac\x92\xd3\x062|" +
+	"\x18\x13\xce\xa8\x03\xc4\x04\xa0n\"\x95\x12`\x15\x13\x8e" +
+	"\x9e-4\xa7\x9a\x12\x01\xa4\xef\xda\x03\xca\x8b\x86*%" +
+	"\xfa\xb6\xbd\xa8,\\\xe1\xa3\xf7\x95\xb5b\x01\x8b}9" +
+	"\xadX\x1e\x02L8K\xc7\xb2)\x16,\x8e\xe6\xe1\x11" +
+	"\xaej\x98pV\xb4\xd7\xc2\xba\xc5\x1ef\x16\xaere" +
+	"\xb4\xd8\xc7\xd3\xe8\x123&\x9c=\xe4kV)U\x81" +
+	"\xdc\xb1g\x92\xe3\xb2\x05\x12j/u\x9b\xa3\xbf\xb7Z" +
+	"\xe1\xdd\xd0\\\xae\x98\xe9\xb4\xe7\xbb\xc7\x02\xc9\x80x0" +
+	"\xe1l\"\xd3fLSr}<\x9d\xaf\xa9\xd83I" +
+	"\xd6f\xd3\x8e\x87\x1e\x1dv:Ci\x8c\x0fiJ\xd1" +
+	"-u{\x10\x9aR\xf7\xd0\xd2\xdcH\x9b#B\xe8\xe3" +
+	"\xc4\x1b\xb6y[h\xd8-\x12P\xbe\x83a\xb26\xa2" +
+	"Z\x97\x01\xc8K\x05\x94\xef\xa4\x09\xa8\xe6sj\xad\xab" +
+	"D\x9a\x87\xb5\x7f<\xd7d\xac\x92\x17\xfbr\"\x95\xdc" +
+	"\x13\xc0\xbd\x00rT@y>C]\xcd\xf0Q\x0a\xd5" +
+	"Lu\xe6_\x97?;~O\xfb\x8f\xecD\xce\xf1>" +
+	"\xc3\x87\x97\x17J9\xa1_%\xd7\x13;\xcd\xf9\xd8\xd2" +
+	"\xe9\xf6}\x971\x0a\x92\xad\xab\x1d\xdf\xc7\x14^P\xb8" +
+	":\x80\x08\x0c\x11\xb0c\xa0\x98\xcf\xf3\xa1\xda\xbf\xf6E" +
+	"\x829\xc0\xac.\xa9\xf5\x92\xaayk\xf0U+\x84\xa5" +
+	"\xcc\xee\xa9^\x10\xab\x15\xa7\x14\xa2\xae\xf5\xff\xed\x13-" +
+	"\xad\x99\x13\xdeR\xd4\xee0{\xc4j\x91\x0dC\x9a\x82" +
+	"\xc6\xc4\x8d\xda\xb7l\xa0U\xb0^@\xf9Agg|" +
+	"9\xe3\xec\x11{g\xf0Ng\x91\xdc\xda\x0a\xd0\xb5\xe2" +
+	" W\xb5\xdc `\xa5\xb6\x06n\xb2\x16\xba\xcbj\xb3" +
+	"F)\xf1\xb4\xcd2'\xf5\xf4\xe7,\xeddk;0" +
+	"\xb1RV\xec=\xd1\x9c\xcb\xe7\x15\xd5SUW\"D" +
+	"\x9f\xads\xc3n\xb7_\x8e\x9e\x14c\xad_Dj\x18" +
+	"bL\xd9\x8c[i\xebn\xb1\x16l-\xad\xdb\x16:" +
+	"\x0b6\xc9\xc2fZ\xc7\xa9Q\xb7\x0b(\xefd\x88\x02" +
+	"\xba\xde\xbf\xc9G\xdb\x81a\xc0\xd8,\xc9\x11\xea\xb3\x8a" +
+	"\x80\xf2\xf7\x18\x86\xf2\xaaV\x13EHU\xfal\x81\x0c" +
+	"\xe6\xb6P\xfb\xaa\xd4\xe7\xb5l\x14J\xb9~\xb5c\xa0" +
+	"\xb2\xae\xd0\xef\x8ai\xfe\x86\xb7\xef\x96\xfe\xb8\xe0\xf0\xf5" +
+	"\x15l5LHS\xaa\xd7\xaf\x85#a\x8a\xe2v\x01" +
+	"\xe5U\x0cE\x1a\xf4\x98p~\xd4X:\x1b(\xab\x9a" +
+	"\xa3B\xfb\xa1\xe5\xabBW\xbd\x043\xb7\xaej-s" +
+	"\xde\x08\xa2V\xadp\x14\xf5o\xacz\xba\x9eO^\xd8" +
+	"Gl\xe2\x9c\x1a\xad\xcd\xa6;L\x99]\xe7\xe9\x95\xf2" +
+	"\x0e\x9e\x1bi\xd5\x14\x92\xa0x\x85\xf4\x90%\xa4\x1eW" +
+	"^6R\xc9\xbb\x05\x94{\x19\"3+.\x93\xbaz" +
+	",!\xd9\xba\x0e\x99\x81\xb8\xf5,\x02\x864\xaddK" +
+	"\xc5N \xba*\xe9\xcec\xfc\xba\x0f\xcf\x8f<\xe2\xed" +
+	"\xb7\xf9\xcdh\x9bi\xa8To$W\x9f\x0e\xb9f\xac" +
+	"\xdfZ_\xd8j\xeb\x18\xb0\xdf\x8d\xae\x1b3\xce\x18\xae" +
+	"\xdd\xd8\xd6i\xdd\xd8\xcdP\xe7\x8aRV\xd6\x95\xf3\x80" +
+	"\xbc&\x8d\xb9A\xdb?\xb7|\x83v5\x81\xef\xd3\xf5" +
+	"\x86\xf9\xb4\x7fE\xf9Rw[)X\x9e\xcb\x87\xf2\x8a" +
+	"j\x06fF1Gn\xcc\xb31\xc5be\xf4\xce\xda" +
+	"\x86\xa7\x7f>s\xf3u\xef\x14\xcd\xd5\xbf$\x865\x02" +
+	"\xca_\xa4\x8b\x02\xe6\xed\xe9\x85\xae\xa6f=\xe6\xed\x1b" +
+	"W;M}\xadl\xdc?\x13:\x8a\xea\xba\xb2\xc2k" +
+	"\xdb\xef\xff\x01\x00\x00\xff\xff\x18V:\xa1"
 
 func init() {
 	schemas.Register(schema_8f4bd412642c9517,
diff --git a/go/sciond/internal/servers/BUILD.bazel b/go/sciond/internal/servers/BUILD.bazel
index a63ad8314..a57014e9d 100644
--- a/go/sciond/internal/servers/BUILD.bazel
+++ b/go/sciond/internal/servers/BUILD.bazel
@@ -26,5 +26,7 @@ go_library(
         "//go/proto:go_default_library",
         "//go/sciond/internal/fetcher:go_default_library",
         "//go/sciond/internal/metrics:go_default_library",
+        "@com_github_opentracing_opentracing_go//:go_default_library",
+        "@com_github_opentracing_opentracing_go//ext:go_default_library",
     ],
 )
diff --git a/go/sciond/internal/servers/api.go b/go/sciond/internal/servers/api.go
index 03d31bc0b..895011ffb 100644
--- a/go/sciond/internal/servers/api.go
+++ b/go/sciond/internal/servers/api.go
@@ -24,6 +24,9 @@ import (
 	"fmt"
 	"net"
 
+	"github.com/opentracing/opentracing-go"
+	opentracingext "github.com/opentracing/opentracing-go/ext"
+
 	"github.com/scionproto/scion/go/lib/common"
 	"github.com/scionproto/scion/go/lib/log"
 	"github.com/scionproto/scion/go/lib/sciond"
@@ -38,16 +41,12 @@ type ConnHandler struct {
 	Conn net.PacketConn
 	// State for request Handlers
 	Handlers map[proto.SCIONDMsg_Which]Handler
-	Logger   log.Logger
 }
 
-func NewConnHandler(conn net.PacketConn,
-	handlers HandlerMap, logger log.Logger) *ConnHandler {
-
+func NewConnHandler(conn net.PacketConn, handlers HandlerMap) *ConnHandler {
 	return &ConnHandler{
 		Conn:     conn,
 		Handlers: handlers,
-		Logger:   logger,
 	}
 }
 
@@ -76,8 +75,19 @@ func (srv *ConnHandler) Handle(b common.RawBytes, address net.Addr) {
 		log.Error("handler not found for capnp message", "which", p.Which)
 		return
 	}
-	ctx, span := tracing.CtxWith(context.Background(), srv.Logger,
-		fmt.Sprintf("%s.handler", p.Which))
+
+	var spanCtx opentracing.SpanContext
+	if len(p.TraceId) > 0 {
+		var err error
+		spanCtx, err = opentracing.GlobalTracer().Extract(opentracing.Binary,
+			bytes.NewReader(p.TraceId))
+		if err != nil {
+			log.Error("Failed to extract span", "err", err)
+		}
+	}
+
+	span, ctx := tracing.CtxWith(context.Background(), fmt.Sprintf("%s.handler", p.Which),
+		opentracingext.RPCServerOption(spanCtx))
 	defer span.Finish()
 	handler.Handle(ctx, srv.Conn, address, p)
 }
diff --git a/go/sciond/internal/servers/server.go b/go/sciond/internal/servers/server.go
index 726d14137..863059f55 100644
--- a/go/sciond/internal/servers/server.go
+++ b/go/sciond/internal/servers/server.go
@@ -39,7 +39,6 @@ type Server struct {
 	address  string
 	filemode os.FileMode
 	handlers map[proto.SCIONDMsg_Which]Handler
-	log      log.Logger
 
 	mu          sync.Mutex
 	listener    net.Listener
@@ -51,15 +50,13 @@ type Server struct {
 // HandlerMap. To start listening on the address, call ListenAndServe.
 //
 // Network must be "unixpacket" or "rsock".
-func NewServer(network string, address string, filemode os.FileMode, handlers HandlerMap,
-	logger log.Logger) *Server {
+func NewServer(network string, address string, filemode os.FileMode, handlers HandlerMap) *Server {
 
 	return &Server{
 		network:  network,
 		address:  address,
 		filemode: filemode,
 		handlers: handlers,
-		log:      logger,
 	}
 }
 
@@ -88,7 +85,7 @@ func (srv *Server) ListenAndServe() error {
 			if strings.Contains(err.Error(), "use of closed network connection") {
 				return err
 			}
-			srv.log.Warn("unable to accept conn", "err", err)
+			log.Warn("unable to accept conn", "err", err)
 			continue
 		}
 
@@ -96,9 +93,9 @@ func (srv *Server) ListenAndServe() error {
 		go func() {
 			defer log.LogPanicAndExit()
 			pconn := conn.(net.PacketConn)
-			hdl := NewConnHandler(pconn, srv.handlers, srv.log)
+			hdl := NewConnHandler(pconn, srv.handlers)
 			if err := hdl.Serve(); err != nil && err != io.EOF {
-				srv.log.Error("Transport handler error", "err", err)
+				log.Error("Transport handler error", "err", err)
 			}
 		}()
 	}
diff --git a/go/sciond/main.go b/go/sciond/main.go
index 47665973c..eec0fa8d1 100644
--- a/go/sciond/main.go
+++ b/go/sciond/main.go
@@ -196,10 +196,10 @@ func realMain() int {
 		10*time.Second, 10*time.Second)
 	defer rcCleaner.Stop()
 	// Start servers
-	rsockServer, shutdownF := NewServer("rsock", cfg.SD.Reliable, handlers, log.Root())
+	rsockServer, shutdownF := NewServer("rsock", cfg.SD.Reliable, handlers)
 	defer shutdownF()
 	StartServer("ReliableSockServer", cfg.SD.Reliable, rsockServer)
-	unixpacketServer, shutdownF := NewServer("unixpacket", cfg.SD.Unix, handlers, log.Root())
+	unixpacketServer, shutdownF := NewServer("unixpacket", cfg.SD.Unix, handlers)
 	defer shutdownF()
 	StartServer("UnixServer", cfg.SD.Unix, unixpacketServer)
 	cfg.Metrics.StartPrometheus()
@@ -260,11 +260,10 @@ func startDiscovery(file idiscovery.Config) error {
 	return err
 }
 
-func NewServer(network string, rsockPath string, handlers servers.HandlerMap,
-	logger log.Logger) (*servers.Server, func()) {
+func NewServer(network string, rsockPath string,
+	handlers servers.HandlerMap) (*servers.Server, func()) {
 
-	server := servers.NewServer(network, rsockPath, os.FileMode(cfg.SD.SocketFileMode), handlers,
-		logger)
+	server := servers.NewServer(network, rsockPath, os.FileMode(cfg.SD.SocketFileMode), handlers)
 	shutdownF := func() {
 		ctx, cancelF := context.WithTimeout(context.Background(), ShutdownWaitTimeout)
 		server.Shutdown(ctx)
diff --git a/proto/sciond.capnp b/proto/sciond.capnp
index 976f5706d..0c93317a0 100644
--- a/proto/sciond.capnp
+++ b/proto/sciond.capnp
@@ -25,6 +25,7 @@ struct SCIONDMsg {
         segTypeHopReq @12 :SegTypeHopReq;
         segTypeHopReply @13 :SegTypeHopReply;
     }
+    traceId @14 :Data;
 }
 
 struct PathReq {
diff --git a/python/topology/jaeger.py b/python/topology/jaeger.py
index 0b4eaaf76..8405353aa 100644
--- a/python/topology/jaeger.py
+++ b/python/topology/jaeger.py
@@ -48,7 +48,7 @@ class JaegerGenerator(object):
             'version': '2',
             'services': {
                 'jaeger': {
-                    'image': 'jaegertracing/all-in-one:1.14.0',
+                    'image': 'jaegertracing/all-in-one:1.16.0',
                     'container_name': name,
                     'user': '%s:%s' % (str(os.getuid()), str(os.getgid())),
                     'ports': [
diff --git a/scion.sh b/scion.sh
index 88f8f8a5c..e8ee6dea1 100755
--- a/scion.sh
+++ b/scion.sh
@@ -401,7 +401,7 @@ cmd_traces() {
         -e BADGER_CONSISTENCY=true \
         -v "$trace_dir:/badger" \
         -p "$port":16686 \
-        jaegertracing/all-in-one:1.14.0
+        jaegertracing/all-in-one:1.16.0
     sleep 3
     x-www-browser "http://localhost:$port"
 }


Test patch:
diff --git a/go/lib/infra/modules/trust/trust_test.go b/go/lib/infra/modules/trust/trust_test.go
index 660a65096..a0214f287 100644
--- a/go/lib/infra/modules/trust/trust_test.go
+++ b/go/lib/infra/modules/trust/trust_test.go
@@ -599,7 +599,6 @@ func setupMessenger(ia addr.IA, conn net.PacketConn, name string) infra.Messenge
 			},
 		},
 		DisableSignatureVerification: true,
-		Logger:                       log.Root().New("name", name),
 	}
 	return messenger.New(config)
 }
diff --git a/go/lib/infra/modules/trust/v2/handlers_test.go b/go/lib/infra/modules/trust/v2/handlers_test.go
index c94f28076..3fdb5f277 100644
--- a/go/lib/infra/modules/trust/v2/handlers_test.go
+++ b/go/lib/infra/modules/trust/v2/handlers_test.go
@@ -306,7 +306,7 @@ func TestChainPushHandler(t *testing.T) {
 		{
 			Name: "empty message",
 			Request: func(_ *gomock.Controller) *infra.Request {
-				return infra.NewRequest(nil, nil, nil, nil, 0)
+				return infra.NewRequest(context.Background(), nil, nil, nil, 0)
 			},
 			Inserter: func(ctrl *gomock.Controller) trust.Inserter {
 				return mock_v2.NewMockInserter(ctrl)
@@ -316,7 +316,7 @@ func TestChainPushHandler(t *testing.T) {
 		{
 			Name: "bad message type",
 			Request: func(_ *gomock.Controller) *infra.Request {
-				return infra.NewRequest(nil, &cert_mgmt.TRC{}, nil, nil, 0)
+				return infra.NewRequest(context.Background(), &cert_mgmt.TRC{}, nil, nil, 0)
 			},
 			Inserter: func(ctrl *gomock.Controller) trust.Inserter {
 				return mock_v2.NewMockInserter(ctrl)
@@ -326,7 +326,7 @@ func TestChainPushHandler(t *testing.T) {
 		{
 			Name: "no response writer",
 			Request: func(_ *gomock.Controller) *infra.Request {
-				return infra.NewRequest(nil, &cert_mgmt.Chain{}, nil, nil, 0)
+				return infra.NewRequest(context.Background(), &cert_mgmt.Chain{}, nil, nil, 0)
 			},
 			Inserter: func(ctrl *gomock.Controller) trust.Inserter {
 				return mock_v2.NewMockInserter(ctrl)
@@ -486,7 +486,7 @@ func TestTRCPushHandler(t *testing.T) {
 		{
 			Name: "empty message",
 			Request: func(_ *gomock.Controller) *infra.Request {
-				return infra.NewRequest(nil, nil, nil, nil, 0)
+				return infra.NewRequest(context.Background(), nil, nil, nil, 0)
 			},
 			Inserter: func(ctrl *gomock.Controller) trust.Inserter {
 				return mock_v2.NewMockInserter(ctrl)
@@ -496,7 +496,7 @@ func TestTRCPushHandler(t *testing.T) {
 		{
 			Name: "bad message type",
 			Request: func(_ *gomock.Controller) *infra.Request {
-				return infra.NewRequest(nil, &cert_mgmt.Chain{}, nil, nil, 0)
+				return infra.NewRequest(context.Background(), &cert_mgmt.Chain{}, nil, nil, 0)
 			},
 			Inserter: func(ctrl *gomock.Controller) trust.Inserter {
 				return mock_v2.NewMockInserter(ctrl)
@@ -506,7 +506,7 @@ func TestTRCPushHandler(t *testing.T) {
 		{
 			Name: "no response writer",
 			Request: func(_ *gomock.Controller) *infra.Request {
-				return infra.NewRequest(nil, &cert_mgmt.TRC{}, nil, nil, 0)
+				return infra.NewRequest(context.Background(), &cert_mgmt.TRC{}, nil, nil, 0)
 			},
 			Inserter: func(ctrl *gomock.Controller) trust.Inserter {
 				return mock_v2.NewMockInserter(ctrl)
diff --git a/go/lib/infra/modules/trust/v2/provider_test.go b/go/lib/infra/modules/trust/v2/provider_test.go
index cd918457a..c3d4a89d4 100644
--- a/go/lib/infra/modules/trust/v2/provider_test.go
+++ b/go/lib/infra/modules/trust/v2/provider_test.go
@@ -15,6 +15,7 @@
 package trust_test
 
 import (
+	"context"
 	"encoding/json"
 	"net"
 	"testing"
@@ -267,7 +268,7 @@ func TestCryptoProviderGetTRC(t *testing.T) {
 				Router:   m.Router,
 			}
 			id := trust.TRCID{ISD: trc1v1.ISD, Version: trc1v1.Version}
-			ptrc, err := provider.GetTRC(nil, id, test.Opts)
+			ptrc, err := provider.GetTRC(context.Background(), id, test.Opts)
 			if test.ExpectedErr != nil {
 				require.Error(t, err)
 				assert.Truef(t, xerrors.Is(err, test.ExpectedErr),
@@ -446,7 +447,7 @@ func TestCryptoProviderGetTRCLatest(t *testing.T) {
 				Router:   m.Router,
 			}
 			id := trust.TRCID{ISD: trc1v1.ISD, Version: scrypto.LatestVer}
-			trcObj, err := provider.GetTRC(nil, id, test.Opts)
+			trcObj, err := provider.GetTRC(context.Background(), id, test.Opts)
 			assert.Equal(t, expected.TRC, trcObj)
 			if test.ExpectedErr != nil {
 				require.Error(t, err)
@@ -1252,7 +1253,7 @@ func TestCryptoProviderGetRawChain(t *testing.T) {
 				Router:   test.Router(t, mctrl),
 			}
 			id := trust.ChainID{IA: test.ChainDesc.IA, Version: test.ChainDesc.Version}
-			raw, err := p.GetRawChain(nil, id, test.Opts)
+			raw, err := p.GetRawChain(context.Background(), id, test.Opts)
 			xtest.AssertErrorsIs(t, err, test.ExpectedErr)
 			assert.Equal(t, test.ExpectedRaw, raw)
 		})
@@ -1331,7 +1332,7 @@ func TestCryptoProviderGetASKey(t *testing.T) {
 				Router:   test.Router(t, mctrl),
 			}
 			id := trust.ChainID{IA: test.ChainDesc.IA, Version: test.ChainDesc.Version}
-			km, err := p.GetASKey(nil, id, test.Opts)
+			km, err := p.GetASKey(context.Background(), id, test.Opts)
 			xtest.AssertErrorsIs(t, err, test.ExpectedErr)
 			assert.Equal(t, test.ExpectedKeyMeta, km)
 		})
diff --git a/go/lib/infra/modules/trust/v2/resolver_test.go b/go/lib/infra/modules/trust/v2/resolver_test.go
index 047230c69..d63d7bde3 100644
--- a/go/lib/infra/modules/trust/v2/resolver_test.go
+++ b/go/lib/infra/modules/trust/v2/resolver_test.go
@@ -56,7 +56,8 @@ func TestResolverTRC(t *testing.T) {
 					m.RPC.EXPECT().GetTRC(gomock.Any(), req, nil).Return(dec.Raw, nil)
 					m.Inserter.EXPECT().InsertTRC(gomock.Any(), dec, gomock.Any()).DoAndReturn(
 						func(_ interface{}, decTRC decoded.TRC, p trust.TRCProviderFunc) error {
-							prev, err := p(nil, trust.TRCID{ISD: 1, Version: req.Version - 1})
+							prev, err := p(context.Background(),
+								trust.TRCID{ISD: 1, Version: req.Version - 1})
 							require.NoError(t, err)
 							assert.Equal(t, req.Version-1, prev.Version)
 							assert.Equal(t, dec, decTRC)