1

I'm using OpenTelemetry Go SDK and I'm trying to set http.response.body.size attribute in my parent span. I'm using otelhttp.NewHandler() to serve the HTTP request:

func NewHTTPHandler(name string, handler http.Handler, tp Provider, attr ...Attribute) http.Handler {
    opts := []otelhttp.Option{
        otelhttp.WithSpanNameFormatter(httpSpanNameFormatter),
    }

    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        attr = append(attr, NewAttribute("http.request.body.size", r.ContentLength))

        opts = append(opts, otelhttp.WithSpanOptions(
            trace.WithAttributes(attr...),
        ))

        otelhttp.NewHandler(handler, name, opts...).ServeHTTP(w, r)
    })
}

At the moment, I could store the http.request.body.size value before processing the HTTP request, but I don't know how to do something similar with the response size.

I tried to wrap the response writer with a callback in order to store the size bytes, and it's working, but when I try to get the span using the request context in order to store this attribute, the span is empty (SpanID is "000000000000"), I could notice it by printing it:

type responseWriterWrapper struct {
    http.ResponseWriter
    contentLength int
    onWrite       func(int) // callback for when Write is called
}

func (rw *responseWriterWrapper) Write(b []byte) (int, error) {
    n, err := rw.ResponseWriter.Write(b)
    rw.contentLength += n
    rw.onWrite(rw.contentLength)
    return n, err
}

func NewHTTPHandler(name string, handler http.Handler, tp Provider, attr ...Attribute) http.Handler {
    opts := []otelhttp.Option{
        otelhttp.WithSpanNameFormatter(httpSpanNameFormatter),
    }

    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        attr = append(attr, NewAttribute("http.request.body.size", r.ContentLength))

        opts = append(opts, otelhttp.WithSpanOptions(
            trace.WithAttributes(attr...),
        ))

        // Setup callback for when Write is called
        rwWrapper := &responseWriterWrapper{
            ResponseWriter: w,
            onWrite: func(length int) {
                span := trace.SpanFromContext(r.Context())
                fmt.Println("SPAN ID:", span.SpanContext().SpanID())
                if span != nil {
                    span.SetAttributes(NewAttribute("http.response.body.size", int64(length)))
                }
            },
        }

        otelhttp.NewHandler(handler, name, opts...).ServeHTTP(rwWrapper, r)
    })
}
msidler
  • 11
  • 1

0 Answers0