feat: add trace in httpc (#2011)

master
chen quan 2 years ago committed by GitHub
parent 0147d7a9d1
commit 6518eb10b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -7,13 +7,20 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"net/http/httptrace"
nurl "net/url" nurl "net/url"
"strings" "strings"
"github.com/zeromicro/go-zero/core/lang" "github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/mapping" "github.com/zeromicro/go-zero/core/mapping"
"github.com/zeromicro/go-zero/core/trace"
"github.com/zeromicro/go-zero/rest/httpc/internal" "github.com/zeromicro/go-zero/rest/httpc/internal"
"github.com/zeromicro/go-zero/rest/internal/header" "github.com/zeromicro/go-zero/rest/internal/header"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/propagation"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
oteltrace "go.opentelemetry.io/otel/trace"
) )
var interceptors = []internal.Interceptor{ var interceptors = []internal.Interceptor{
@ -150,17 +157,47 @@ func fillPath(u *nurl.URL, val map[string]interface{}) error {
} }
func request(r *http.Request, cli client) (*http.Response, error) { func request(r *http.Request, cli client) (*http.Response, error) {
var respHandlers []internal.ResponseHandler tracer := otel.GetTracerProvider().Tracer(trace.TraceName)
for _, interceptor := range interceptors { propagator := otel.GetTextMapPropagator()
spanName := r.URL.Path
ctx, span := tracer.Start(
r.Context(),
spanName,
oteltrace.WithSpanKind(oteltrace.SpanKindClient),
oteltrace.WithAttributes(semconv.HTTPClientAttributesFromHTTPRequest(r)...),
)
defer span.End()
respHandlers := make([]internal.ResponseHandler, len(interceptors))
for i, interceptor := range interceptors {
var h internal.ResponseHandler var h internal.ResponseHandler
r, h = interceptor(r) r, h = interceptor(r)
respHandlers = append(respHandlers, h) respHandlers[i] = h
} }
clientTrace := httptrace.ContextClientTrace(ctx)
if clientTrace != nil {
ctx = httptrace.WithClientTrace(ctx, clientTrace)
}
r = r.WithContext(ctx)
span.SetAttributes(semconv.HTTPClientAttributesFromHTTPRequest(r)...)
propagator.Inject(ctx, propagation.HeaderCarrier(r.Header))
resp, err := cli.do(r) resp, err := cli.do(r)
for i := len(respHandlers) - 1; i >= 0; i-- { for i := len(respHandlers) - 1; i >= 0; i-- {
respHandlers[i](resp, err) respHandlers[i](resp, err)
} }
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return resp, err
}
span.SetAttributes(semconv.HTTPAttributesFromHTTPStatusCode(resp.StatusCode)...)
span.SetStatus(semconv.SpanStatusFromHTTPStatusCode(resp.StatusCode))
return resp, err return resp, err
} }

@ -4,15 +4,25 @@ import (
"context" "context"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"net/http/httptrace"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
ztrace "github.com/zeromicro/go-zero/core/trace"
"github.com/zeromicro/go-zero/rest/httpx" "github.com/zeromicro/go-zero/rest/httpx"
"github.com/zeromicro/go-zero/rest/internal/header" "github.com/zeromicro/go-zero/rest/internal/header"
"github.com/zeromicro/go-zero/rest/router" "github.com/zeromicro/go-zero/rest/router"
"go.opentelemetry.io/otel/trace"
) )
func TestDoRequest(t *testing.T) { func TestDoRequest(t *testing.T) {
ztrace.StartAgent(ztrace.Config{
Name: "go-zero-test",
Endpoint: "http://localhost:14268/api/traces",
Batcher: "jaeger",
Sampler: 1.0,
})
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
})) }))
defer svr.Close() defer svr.Close()
@ -21,6 +31,8 @@ func TestDoRequest(t *testing.T) {
resp, err := DoRequest(req) resp, err := DoRequest(req)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
spanContext := trace.SpanContextFromContext(resp.Request.Context())
assert.True(t, spanContext.IsValid())
} }
func TestDoRequest_NotFound(t *testing.T) { func TestDoRequest_NotFound(t *testing.T) {
@ -187,3 +199,17 @@ func TestDo_Json(t *testing.T) {
_, err = Do(context.Background(), http.MethodPost, svr.URL+"/nodes/:key", data) _, err = Do(context.Background(), http.MethodPost, svr.URL+"/nodes/:key", data)
assert.NotNil(t, err) assert.NotNil(t, err)
} }
func TestDo_WithClientHttpTrace(t *testing.T) {
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
defer svr.Close()
_, err := Do(httptrace.WithClientTrace(context.Background(),
&httptrace.ClientTrace{
DNSStart: func(info httptrace.DNSStartInfo) {
assert.Equal(t, "localhost", info.Host)
},
}), http.MethodGet, svr.URL, nil)
assert.Nil(t, err)
}

Loading…
Cancel
Save