diff --git a/ingress/origin_proxy.go b/ingress/origin_proxy.go index e99e002e..90371dfa 100644 --- a/ingress/origin_proxy.go +++ b/ingress/origin_proxy.go @@ -1,6 +1,7 @@ package ingress import ( + "fmt" "net" "net/http" @@ -49,7 +50,13 @@ func (o *httpService) RoundTrip(req *http.Request) (*http.Response, error) { } func (o *statusCode) RoundTrip(_ *http.Request) (*http.Response, error) { - return o.resp, nil + resp := &http.Response{ + StatusCode: o.code, + Status: fmt.Sprintf("%d %s", o.code, http.StatusText(o.code)), + Body: new(NopReadCloser), + } + + return resp, nil } func (o *rawTCPService) EstablishConnection(dest string) (OriginConnection, error) { diff --git a/ingress/origin_service.go b/ingress/origin_service.go index c96e4608..38ceeda5 100644 --- a/ingress/origin_service.go +++ b/ingress/origin_service.go @@ -238,20 +238,15 @@ func (o helloWorld) MarshalJSON() ([]byte, error) { // statusCode is an OriginService that just responds with a given HTTP status. // Typical use-case is "user wants the catch-all rule to just respond 404". type statusCode struct { - resp *http.Response + code int } func newStatusCode(status int) statusCode { - resp := &http.Response{ - StatusCode: status, - Status: fmt.Sprintf("%d %s", status, http.StatusText(status)), - Body: new(NopReadCloser), - } - return statusCode{resp: resp} + return statusCode{code: status} } func (o *statusCode) String() string { - return fmt.Sprintf("http_status:%d", o.resp.StatusCode) + return fmt.Sprintf("http_status:%d", o.code) } func (o *statusCode) start( diff --git a/proxy/proxy.go b/proxy/proxy.go index 32e3d678..661ab363 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -11,7 +11,6 @@ import ( "github.com/pkg/errors" "github.com/rs/zerolog" "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" "github.com/cloudflare/cloudflared/carrier" @@ -197,10 +196,11 @@ func (p *Proxy) proxyHTTPRequest( _, ttfbSpan := tr.Tracer().Start(tr.Context(), "ttfb_origin") resp, err := httpService.RoundTrip(roundTripReq) if err != nil { - tracing.EndWithStatus(ttfbSpan, codes.Error, "") + tracing.EndWithErrorStatus(ttfbSpan, err) return errors.Wrap(err, "Unable to reach the origin service. The service may be down or it may not be responding to traffic from cloudflared") } - tracing.EndWithStatus(ttfbSpan, codes.Ok, resp.Status) + + tracing.EndWithStatusCode(ttfbSpan, resp.StatusCode) defer resp.Body.Close() // resp headers can be nil diff --git a/tracing/tracing.go b/tracing/tracing.go index 927798b3..e9172cd5 100644 --- a/tracing/tracing.go +++ b/tracing/tracing.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "math" "net/http" "os" "runtime" @@ -29,6 +30,9 @@ const ( TracerContextNameOverride = "uber-trace-id" IntCloudflaredTracingHeader = "cf-int-cloudflared-tracing" + + MaxErrorDescriptionLen = 100 + traceHttpStatusCodeKey = "upstreamStatusCode" ) var ( @@ -130,12 +134,35 @@ func (cft *TracedRequest) AddSpans(headers http.Header, log *zerolog.Logger) { headers[CanonicalCloudflaredTracingHeader] = []string{enc} } -// EndWithStatus will set a status for the span and then end it. -func EndWithStatus(span trace.Span, code codes.Code, status string) { +// EndWithErrorStatus will set a status for the span and then end it. +func EndWithErrorStatus(span trace.Span, err error) { + endSpan(span, -1, codes.Error, err) +} + +// EndWithStatusCode will set a status for the span and then end it. +func EndWithStatusCode(span trace.Span, statusCode int) { + endSpan(span, statusCode, codes.Ok, nil) +} + +// EndWithErrorStatus will set a status for the span and then end it. +func endSpan(span trace.Span, upstreamStatusCode int, spanStatusCode codes.Code, err error) { if span == nil { return } - span.SetStatus(code, status) + + if upstreamStatusCode > 0 { + span.SetAttributes(attribute.Int(traceHttpStatusCodeKey, upstreamStatusCode)) + } + + // add error to status buf cap description + errDescription := "" + if err != nil { + errDescription = err.Error() + l := int(math.Min(float64(len(errDescription)), MaxErrorDescriptionLen)) + errDescription = errDescription[:l] + } + + span.SetStatus(spanStatusCode, errDescription) span.End() }