diff --git a/connection/connection.go b/connection/connection.go index bcc24b64..5200f4bb 100644 --- a/connection/connection.go +++ b/connection/connection.go @@ -123,23 +123,24 @@ func (t Type) String() string { // OriginProxy is how data flows from cloudflared to the origin services running behind it. type OriginProxy interface { - ProxyHTTP(w ResponseWriter, tr *tracing.TracedRequest, isWebsocket bool) error + ProxyHTTP(w ResponseWriter, tr *tracing.TracedHTTPRequest, isWebsocket bool) error ProxyTCP(ctx context.Context, rwa ReadWriteAcker, req *TCPRequest) error } // TCPRequest defines the input format needed to perform a TCP proxy. type TCPRequest struct { - Dest string - CFRay string - LBProbe bool - FlowID string + Dest string + CFRay string + LBProbe bool + FlowID string + CfTraceID string } // ReadWriteAcker is a readwriter with the ability to Acknowledge to the downstream (edge) that the origin has // accepted the connection. type ReadWriteAcker interface { io.ReadWriter - AckConnection() error + AckConnection(tracePropagation string) error } // HTTPResponseReadWriteAcker is an HTTP implementation of ReadWriteAcker. @@ -168,7 +169,7 @@ func (h *HTTPResponseReadWriteAcker) Write(p []byte) (int, error) { // AckConnection acks an HTTP connection by sending a switch protocols status code that enables the caller to // upgrade to streams. -func (h *HTTPResponseReadWriteAcker) AckConnection() error { +func (h *HTTPResponseReadWriteAcker) AckConnection(tracePropagation string) error { resp := &http.Response{ Status: switchingProtocolText, StatusCode: http.StatusSwitchingProtocols, @@ -179,6 +180,10 @@ func (h *HTTPResponseReadWriteAcker) AckConnection() error { resp.Header = websocket.NewResponseHeader(h.req) } + if tracePropagation != "" { + resp.Header.Add(tracing.CanonicalCloudflaredTracingHeader, tracePropagation) + } + return h.w.WriteRespHeaders(resp.StatusCode, resp.Header) } diff --git a/connection/connection_test.go b/connection/connection_test.go index b8c3b674..ae37db75 100644 --- a/connection/connection_test.go +++ b/connection/connection_test.go @@ -30,6 +30,8 @@ var ( testLargeResp = make([]byte, largeFileSize) ) +var _ ReadWriteAcker = (*HTTPResponseReadWriteAcker)(nil) + type testRequest struct { name string endpoint string @@ -60,7 +62,7 @@ type mockOriginProxy struct{} func (moc *mockOriginProxy) ProxyHTTP( w ResponseWriter, - tr *tracing.TracedRequest, + tr *tracing.TracedHTTPRequest, isWebsocket bool, ) error { req := tr.Request diff --git a/connection/h2mux.go b/connection/h2mux.go index 0bd35cbe..b78b433f 100644 --- a/connection/h2mux.go +++ b/connection/h2mux.go @@ -69,6 +69,7 @@ func NewH2muxConnection( connIndex uint8, observer *Observer, gracefulShutdownC <-chan struct{}, + log *zerolog.Logger, ) (*h2muxConnection, error, bool) { h := &h2muxConnection{ orchestrator: orchestrator, @@ -79,6 +80,7 @@ func NewH2muxConnection( observer: observer, gracefulShutdownC: gracefulShutdownC, newRPCClientFunc: newRegistrationRPCClient, + log: log, } // Establish a muxed connection with the edge @@ -234,7 +236,7 @@ func (h *h2muxConnection) ServeStream(stream *h2mux.MuxedStream) error { return err } - err = originProxy.ProxyHTTP(respWriter, tracing.NewTracedRequest(req), sourceConnectionType == TypeWebsocket) + err = originProxy.ProxyHTTP(respWriter, tracing.NewTracedHTTPRequest(req, h.log), sourceConnectionType == TypeWebsocket) if err != nil { respWriter.WriteErrorResponse() } diff --git a/connection/h2mux_test.go b/connection/h2mux_test.go index cf2337ec..53c28227 100644 --- a/connection/h2mux_test.go +++ b/connection/h2mux_test.go @@ -48,7 +48,7 @@ func newH2MuxConnection(t require.TestingT) (*h2muxConnection, *h2mux.Muxer) { }() var connIndex = uint8(0) testObserver := NewObserver(&log, &log) - h2muxConn, err, _ := NewH2muxConnection(testOrchestrator, testGracePeriod, testMuxerConfig, originConn, connIndex, testObserver, nil) + h2muxConn, err, _ := NewH2muxConnection(testOrchestrator, testGracePeriod, testMuxerConfig, originConn, connIndex, testObserver, nil, &log) require.NoError(t, err) return h2muxConn, <-edgeMuxChan } diff --git a/connection/http2.go b/connection/http2.go index f7ead1f0..1b78d748 100644 --- a/connection/http2.go +++ b/connection/http2.go @@ -132,7 +132,7 @@ func (c *HTTP2Connection) ServeHTTP(w http.ResponseWriter, r *http.Request) { case TypeWebsocket, TypeHTTP: stripWebsocketUpgradeHeader(r) // Check for tracing on request - tr := tracing.NewTracedRequest(r) + tr := tracing.NewTracedHTTPRequest(r, c.log) if err := originProxy.ProxyHTTP(respWriter, tr, connType == TypeWebsocket); err != nil { err := fmt.Errorf("Failed to proxy HTTP: %w", err) c.log.Error().Err(err) diff --git a/connection/quic.go b/connection/quic.go index 7adc03c2..12e1d2b6 100644 --- a/connection/quic.go +++ b/connection/quic.go @@ -197,7 +197,7 @@ func (q *QUICConnection) dispatchRequest(ctx context.Context, stream *quicpogs.R switch request.Type { case quicpogs.ConnectionTypeHTTP, quicpogs.ConnectionTypeWebsocket: - tracedReq, err := buildHTTPRequest(ctx, request, stream) + tracedReq, err := buildHTTPRequest(ctx, request, stream, q.logger) if err != nil { return err } @@ -208,8 +208,9 @@ func (q *QUICConnection) dispatchRequest(ctx context.Context, stream *quicpogs.R rwa := &streamReadWriteAcker{stream} metadata := request.MetadataMap() return originProxy.ProxyTCP(ctx, rwa, &TCPRequest{ - Dest: request.Dest, - FlowID: metadata[QUICMetadataFlowID], + Dest: request.Dest, + FlowID: metadata[QUICMetadataFlowID], + CfTraceID: metadata[tracing.TracerContextName], }) } return nil @@ -296,8 +297,12 @@ type streamReadWriteAcker struct { } // AckConnection acks response back to the proxy. -func (s *streamReadWriteAcker) AckConnection() error { - return s.WriteConnectResponseData(nil) +func (s *streamReadWriteAcker) AckConnection(tracePropagation string) error { + metadata := quicpogs.Metadata{ + Key: tracing.CanonicalCloudflaredTracingHeader, + Val: tracePropagation, + } + return s.WriteConnectResponseData(nil, metadata) } // httpResponseAdapter translates responses written by the HTTP Proxy into ones that can be used in QUIC. @@ -325,7 +330,12 @@ func (hrw httpResponseAdapter) WriteErrorResponse(err error) { hrw.WriteConnectResponseData(err, quicpogs.Metadata{Key: "HttpStatus", Val: strconv.Itoa(http.StatusBadGateway)}) } -func buildHTTPRequest(ctx context.Context, connectRequest *quicpogs.ConnectRequest, body io.ReadCloser) (*tracing.TracedRequest, error) { +func buildHTTPRequest( + ctx context.Context, + connectRequest *quicpogs.ConnectRequest, + body io.ReadCloser, + log *zerolog.Logger, +) (*tracing.TracedHTTPRequest, error) { metadata := connectRequest.MetadataMap() dest := connectRequest.Dest method := metadata[HTTPMethodKey] @@ -367,7 +377,7 @@ func buildHTTPRequest(ctx context.Context, connectRequest *quicpogs.ConnectReque stripWebsocketUpgradeHeader(req) // Check for tracing on request - tracedReq := tracing.NewTracedRequest(req) + tracedReq := tracing.NewTracedHTTPRequest(req, log) return tracedReq, err } diff --git a/connection/quic_test.go b/connection/quic_test.go index 33da98ac..2557e67b 100644 --- a/connection/quic_test.go +++ b/connection/quic_test.go @@ -36,6 +36,8 @@ var ( } ) +var _ ReadWriteAcker = (*streamReadWriteAcker)(nil) + // TestQUICServer tests if a quic server accepts and responds to a quic client with the acceptance protocol. // It also serves as a demonstration for communication with the QUIC connection started by a cloudflared. func TestQUICServer(t *testing.T) { @@ -220,7 +222,7 @@ func quicServer( type mockOriginProxyWithRequest struct{} -func (moc *mockOriginProxyWithRequest) ProxyHTTP(w ResponseWriter, tr *tracing.TracedRequest, isWebsocket bool) error { +func (moc *mockOriginProxyWithRequest) ProxyHTTP(w ResponseWriter, tr *tracing.TracedHTTPRequest, isWebsocket bool) error { // These are a series of crude tests to ensure the headers and http related data is transferred from // metadata. r := tr.Request @@ -475,9 +477,10 @@ func TestBuildHTTPRequest(t *testing.T) { }, } + log := zerolog.Nop() for _, test := range tests { t.Run(test.name, func(t *testing.T) { - req, err := buildHTTPRequest(context.Background(), test.connectRequest, test.body) + req, err := buildHTTPRequest(context.Background(), test.connectRequest, test.body, &log) assert.NoError(t, err) test.req = test.req.WithContext(req.Context()) assert.Equal(t, test.req, req.Request) @@ -486,7 +489,7 @@ func TestBuildHTTPRequest(t *testing.T) { } func (moc *mockOriginProxyWithRequest) ProxyTCP(ctx context.Context, rwa ReadWriteAcker, tcpRequest *TCPRequest) error { - rwa.AckConnection() + rwa.AckConnection("") io.Copy(rwa, rwa) return nil } diff --git a/orchestration/orchestrator_test.go b/orchestration/orchestrator_test.go index dfac28a0..dc94d29c 100644 --- a/orchestration/orchestrator_test.go +++ b/orchestration/orchestrator_test.go @@ -355,7 +355,7 @@ func proxyHTTP(originProxy connection.OriginProxy, hostname string) (*http.Respo return nil, err } - err = originProxy.ProxyHTTP(respWriter, tracing.NewTracedRequest(req), false) + err = originProxy.ProxyHTTP(respWriter, tracing.NewTracedHTTPRequest(req, &log), false) if err != nil { return nil, err } @@ -604,7 +604,7 @@ func TestPersistentConnection(t *testing.T) { respWriter, err := connection.NewHTTP2RespWriter(req, wsRespReadWriter, connection.TypeWebsocket, &log) require.NoError(t, err) - err = originProxy.ProxyHTTP(respWriter, tracing.NewTracedRequest(req), true) + err = originProxy.ProxyHTTP(respWriter, tracing.NewTracedHTTPRequest(req, &log), true) require.NoError(t, err) }() diff --git a/proxy/proxy.go b/proxy/proxy.go index 19f14778..0c2c21c0 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -63,7 +63,7 @@ func NewOriginProxy( // a simple roundtrip or a tcp/websocket dial depending on ingres rule setup. func (p *Proxy) ProxyHTTP( w connection.ResponseWriter, - tr *tracing.TracedRequest, + tr *tracing.TracedHTTPRequest, isWebsocket bool, ) error { incrementRequests() @@ -108,7 +108,7 @@ func (p *Proxy) ProxyHTTP( } rws := connection.NewHTTPResponseReadWriterAcker(w, req) - if err := p.proxyStream(req.Context(), rws, dest, originProxy); err != nil { + if err := p.proxyStream(tr.ToTracedContext(), rws, dest, originProxy); err != nil { rule, srv := ruleField(p.ingressRules, ruleNum) p.logRequestError(err, cfRay, "", rule, srv) return err @@ -137,9 +137,11 @@ func (p *Proxy) ProxyTCP( serveCtx, cancel := context.WithCancel(ctx) defer cancel() + tracedCtx := tracing.NewTracedContext(serveCtx, req.CfTraceID, p.log) + p.log.Debug().Str(LogFieldFlowID, req.FlowID).Msg("tcp proxy stream started") - if err := p.proxyStream(serveCtx, rwa, req.Dest, p.warpRouting.Proxy); err != nil { + if err := p.proxyStream(tracedCtx, rwa, req.Dest, p.warpRouting.Proxy); err != nil { p.logRequestError(err, req.CFRay, req.FlowID, "", ingress.ServiceWarpRouting) return err } @@ -160,7 +162,7 @@ func ruleField(ing ingress.Ingress, ruleNum int) (ruleID string, srv string) { // ProxyHTTPRequest proxies requests of underlying type http and websocket to the origin service. func (p *Proxy) proxyHTTPRequest( w connection.ResponseWriter, - tr *tracing.TracedRequest, + tr *tracing.TracedHTTPRequest, httpService ingress.HTTPOriginProxy, isWebsocket bool, disableChunkedEncoding bool, @@ -211,7 +213,7 @@ func (p *Proxy) proxyHTTPRequest( } // Add spans to response header (if available) - tr.AddSpans(resp.Header, p.log) + tr.AddSpans(resp.Header) err = w.WriteRespHeaders(resp.StatusCode, resp.Header) if err != nil { @@ -248,17 +250,23 @@ func (p *Proxy) proxyHTTPRequest( // proxyStream proxies type TCP and other underlying types if the connection is defined as a stream oriented // ingress rule. func (p *Proxy) proxyStream( - ctx context.Context, + tr *tracing.TracedContext, rwa connection.ReadWriteAcker, dest string, connectionProxy ingress.StreamBasedOriginProxy, ) error { + ctx := tr.Context + _, connectSpan := tr.Tracer().Start(ctx, "stream_connect") originConn, err := connectionProxy.EstablishConnection(ctx, dest) if err != nil { + tracing.EndWithErrorStatus(connectSpan, err) return err } + connectSpan.End() - if err := rwa.AckConnection(); err != nil { + encodedSpans := tr.GetSpans() + + if err := rwa.AckConnection(encodedSpans); err != nil { return err } diff --git a/proxy/proxy_test.go b/proxy/proxy_test.go index 0e0019f1..f85281b3 100644 --- a/proxy/proxy_test.go +++ b/proxy/proxy_test.go @@ -157,7 +157,8 @@ func testProxyHTTP(proxy connection.OriginProxy) func(t *testing.T) { req, err := http.NewRequest(http.MethodGet, "http://localhost:8080", nil) require.NoError(t, err) - err = proxy.ProxyHTTP(responseWriter, tracing.NewTracedRequest(req), false) + log := zerolog.Nop() + err = proxy.ProxyHTTP(responseWriter, tracing.NewTracedHTTPRequest(req, &log), false) require.NoError(t, err) for _, tag := range testTags { assert.Equal(t, tag.Value, req.Header.Get(TagHeaderNamePrefix+tag.Name)) @@ -184,7 +185,8 @@ func testProxyWebsocket(proxy connection.OriginProxy) func(t *testing.T) { errGroup, ctx := errgroup.WithContext(ctx) errGroup.Go(func() error { - err = proxy.ProxyHTTP(responseWriter, tracing.NewTracedRequest(req), true) + log := zerolog.Nop() + err = proxy.ProxyHTTP(responseWriter, tracing.NewTracedHTTPRequest(req, &log), true) require.NoError(t, err) require.Equal(t, http.StatusSwitchingProtocols, responseWriter.Code) @@ -245,7 +247,8 @@ func testProxySSE(proxy connection.OriginProxy) func(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - err = proxy.ProxyHTTP(responseWriter, tracing.NewTracedRequest(req), false) + log := zerolog.Nop() + err = proxy.ProxyHTTP(responseWriter, tracing.NewTracedHTTPRequest(req, &log), false) require.NoError(t, err) require.Equal(t, http.StatusOK, responseWriter.Code) @@ -357,7 +360,7 @@ func runIngressTestScenarios(t *testing.T, unvalidatedIngress []config.Unvalidat req, err := http.NewRequest(http.MethodGet, test.url, nil) require.NoError(t, err) - err = proxy.ProxyHTTP(responseWriter, tracing.NewTracedRequest(req), false) + err = proxy.ProxyHTTP(responseWriter, tracing.NewTracedHTTPRequest(req, &log), false) require.NoError(t, err) assert.Equal(t, test.expectedStatus, responseWriter.Code) @@ -404,7 +407,7 @@ func TestProxyError(t *testing.T) { req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1", nil) assert.NoError(t, err) - assert.Error(t, proxy.ProxyHTTP(responseWriter, tracing.NewTracedRequest(req), false)) + assert.Error(t, proxy.ProxyHTTP(responseWriter, tracing.NewTracedHTTPRequest(req, &log), false)) } type replayer struct { @@ -682,7 +685,8 @@ func TestConnections(t *testing.T) { rwa := connection.NewHTTPResponseReadWriterAcker(respWriter, req) err = proxy.ProxyTCP(ctx, rwa, &connection.TCPRequest{Dest: dest}) } else { - err = proxy.ProxyHTTP(respWriter, tracing.NewTracedRequest(req), test.args.connectionType == connection.TypeWebsocket) + log := zerolog.Nop() + err = proxy.ProxyHTTP(respWriter, tracing.NewTracedHTTPRequest(req, &log), test.args.connectionType == connection.TypeWebsocket) } cancel() diff --git a/supervisor/tunnel.go b/supervisor/tunnel.go index 4f208dd4..2abf09f5 100644 --- a/supervisor/tunnel.go +++ b/supervisor/tunnel.go @@ -557,6 +557,7 @@ func ServeH2mux( connIndex, config.Observer, gracefulShutdownC, + config.Log, ) if err != nil { if !recoverable { diff --git a/tracing/tracing.go b/tracing/tracing.go index e9172cd5..7eba4c52 100644 --- a/tracing/tracing.go +++ b/tracing/tracing.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "runtime" + "strings" "github.com/rs/zerolog" otelContrib "go.opentelemetry.io/contrib/propagators/jaeger" @@ -33,6 +34,9 @@ const ( MaxErrorDescriptionLen = 100 traceHttpStatusCodeKey = "upstreamStatusCode" + + traceID128bitsWidth = 128 / 4 + separator = ":" ) var ( @@ -66,22 +70,50 @@ func Init(version string) { cloudflaredVersionAttribute = semconv.ProcessRuntimeVersionKey.String(version) } -type TracedRequest struct { +type TracedHTTPRequest struct { *http.Request - trace.TracerProvider - exporter InMemoryClient + *cfdTracer } -// NewTracedRequest creates a new tracer for the current request context. -func NewTracedRequest(req *http.Request) *TracedRequest { +// NewTracedHTTPRequest creates a new tracer for the current HTTP request context. +func NewTracedHTTPRequest(req *http.Request, log *zerolog.Logger) *TracedHTTPRequest { ctx, exists := extractTrace(req) if !exists { - return &TracedRequest{req, trace.NewNoopTracerProvider(), &NoopOtlpClient{}} + return &TracedHTTPRequest{req, &cfdTracer{trace.NewNoopTracerProvider(), &NoopOtlpClient{}, log}} } + return &TracedHTTPRequest{req.WithContext(ctx), newCfdTracer(ctx, log)} +} + +func (tr *TracedHTTPRequest) ToTracedContext() *TracedContext { + return &TracedContext{tr.Context(), tr.cfdTracer} +} + +type TracedContext struct { + context.Context + *cfdTracer +} + +// NewTracedHTTPRequest creates a new tracer for the current HTTP request context. +func NewTracedContext(ctx context.Context, traceContext string, log *zerolog.Logger) *TracedContext { + ctx, exists := extractTraceFromString(ctx, traceContext) + if !exists { + return &TracedContext{ctx, &cfdTracer{trace.NewNoopTracerProvider(), &NoopOtlpClient{}, log}} + } + return &TracedContext{ctx, newCfdTracer(ctx, log)} +} + +type cfdTracer struct { + trace.TracerProvider + exporter InMemoryClient + log *zerolog.Logger +} + +// NewCfdTracer creates a new tracer for the current request context. +func newCfdTracer(ctx context.Context, log *zerolog.Logger) *cfdTracer { mc := new(InMemoryOtlpClient) - exp, err := otlptrace.New(req.Context(), mc) + exp, err := otlptrace.New(ctx, mc) if err != nil { - return &TracedRequest{req, trace.NewNoopTracerProvider(), &NoopOtlpClient{}} + return &cfdTracer{trace.NewNoopTracerProvider(), &NoopOtlpClient{}, log} } tp := tracesdk.NewTracerProvider( // We want to dump to in-memory exporter immediately @@ -98,36 +130,43 @@ func NewTracedRequest(req *http.Request) *TracedRequest { )), ) - return &TracedRequest{req.WithContext(ctx), tp, mc} + return &cfdTracer{tp, mc, log} } -func (cft *TracedRequest) Tracer() trace.Tracer { +func (cft *cfdTracer) Tracer() trace.Tracer { return cft.TracerProvider.Tracer(tracerInstrumentName) } -// Spans returns the spans as base64 encoded protobuf otlp traces. -func (cft *TracedRequest) AddSpans(headers http.Header, log *zerolog.Logger) { - if headers == nil { - log.Error().Msgf("provided headers map is nil") - return - } - +// GetSpans returns the spans as base64 encoded string of protobuf otlp traces. +func (cft *cfdTracer) GetSpans() (enc string) { enc, err := cft.exporter.Spans() switch err { case nil: break case errNoTraces: - log.Error().Err(err).Msgf("expected traces to be available") + cft.log.Error().Err(err).Msgf("expected traces to be available") return case errNoopTracer: return // noop tracer has no traces default: - log.Error().Err(err) + cft.log.Error().Err(err) return } + return +} + +// AddSpans assigns spans as base64 encoded protobuf otlp traces to provided +// HTTP headers. +func (cft *cfdTracer) AddSpans(headers http.Header) { + if headers == nil { + cft.log.Error().Msgf("provided headers map is nil") + return + } + + enc := cft.GetSpans() // No need to add header if no traces if enc == "" { - log.Error().Msgf("no traces provided and no error from exporter") + cft.log.Error().Msgf("no traces provided and no error from exporter") return } @@ -166,6 +205,33 @@ func endSpan(span trace.Span, upstreamStatusCode int, spanStatusCode codes.Code, span.End() } +// extractTraceFromString will extract the trace information from the provided +// propagated trace string context. +func extractTraceFromString(ctx context.Context, trace string) (context.Context, bool) { + if trace == "" { + return ctx, false + } + // Jaeger specific separator + parts := strings.Split(trace, separator) + if len(parts) != 4 { + return ctx, false + } + if parts[0] == "" { + return ctx, false + } + // Correctly left pad the trace to a length of 32 + if len(parts[0]) < traceID128bitsWidth { + left := traceID128bitsWidth - len(parts[0]) + parts[0] = strings.Repeat("0", left) + parts[0] + trace = strings.Join(parts, separator) + } + + // Override the 'cf-trace-id' as 'uber-trace-id' so the jaeger propagator can extract it. + traceHeader := map[string]string{TracerContextNameOverride: trace} + remoteCtx := otel.GetTextMapPropagator().Extract(ctx, propagation.MapCarrier(traceHeader)) + return remoteCtx, true +} + // extractTrace attempts to check for a cf-trace-id from a request and return the // trace context with the provided http.Request. func extractTrace(req *http.Request) (context.Context, bool) { diff --git a/tracing/tracing_test.go b/tracing/tracing_test.go index 68a272fc..5750056e 100644 --- a/tracing/tracing_test.go +++ b/tracing/tracing_test.go @@ -14,38 +14,42 @@ import ( ) func TestNewCfTracer(t *testing.T) { + log := zerolog.Nop() req := httptest.NewRequest("GET", "http://localhost", nil) req.Header.Add(TracerContextName, "14cb070dde8e51fc5ae8514e69ba42ca:b38f1bf5eae406f3:0:1") - tr := NewTracedRequest(req) + tr := NewTracedHTTPRequest(req, &log) assert.NotNil(t, tr) assert.IsType(t, tracesdk.NewTracerProvider(), tr.TracerProvider) assert.IsType(t, &InMemoryOtlpClient{}, tr.exporter) } func TestNewCfTracerMultiple(t *testing.T) { + log := zerolog.Nop() req := httptest.NewRequest("GET", "http://localhost", nil) req.Header.Add(TracerContextName, "1241ce3ecdefc68854e8514e69ba42ca:b38f1bf5eae406f3:0:1") req.Header.Add(TracerContextName, "14cb070dde8e51fc5ae8514e69ba42ca:b38f1bf5eae406f3:0:1") - tr := NewTracedRequest(req) + tr := NewTracedHTTPRequest(req, &log) assert.NotNil(t, tr) assert.IsType(t, tracesdk.NewTracerProvider(), tr.TracerProvider) assert.IsType(t, &InMemoryOtlpClient{}, tr.exporter) } func TestNewCfTracerNilHeader(t *testing.T) { + log := zerolog.Nop() req := httptest.NewRequest("GET", "http://localhost", nil) req.Header[http.CanonicalHeaderKey(TracerContextName)] = nil - tr := NewTracedRequest(req) + tr := NewTracedHTTPRequest(req, &log) assert.NotNil(t, tr) assert.IsType(t, trace.NewNoopTracerProvider(), tr.TracerProvider) assert.IsType(t, &NoopOtlpClient{}, tr.exporter) } func TestNewCfTracerInvalidHeaders(t *testing.T) { + log := zerolog.Nop() req := httptest.NewRequest("GET", "http://localhost", nil) for _, test := range [][]string{nil, {""}} { req.Header[http.CanonicalHeaderKey(TracerContextName)] = test - tr := NewTracedRequest(req) + tr := NewTracedHTTPRequest(req, &log) assert.NotNil(t, tr) assert.IsType(t, trace.NewNoopTracerProvider(), tr.TracerProvider) assert.IsType(t, &NoopOtlpClient{}, tr.exporter) @@ -53,9 +57,10 @@ func TestNewCfTracerInvalidHeaders(t *testing.T) { } func TestAddingSpansWithNilMap(t *testing.T) { + log := zerolog.Nop() req := httptest.NewRequest("GET", "http://localhost", nil) req.Header.Add(TracerContextName, "14cb070dde8e51fc5ae8514e69ba42ca:b38f1bf5eae406f3:0:1") - tr := NewTracedRequest(req) + tr := NewTracedHTTPRequest(req, &log) exporter := tr.exporter.(*InMemoryOtlpClient) @@ -65,5 +70,5 @@ func TestAddingSpansWithNilMap(t *testing.T) { assert.NoError(t, err) // a panic shouldn't occur - tr.AddSpans(nil, &zerolog.Logger{}) + tr.AddSpans(nil) }