1
0
Fork 0

Migrate to opentelemetry

This commit is contained in:
Jesse Haka 2024-01-08 10:10:06 +02:00 committed by GitHub
parent 45bb00be04
commit 4ddef9830b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
89 changed files with 2113 additions and 3898 deletions

View file

@ -8,15 +8,15 @@ import (
"strings"
goauth "github.com/abbot/go-http-auth"
"github.com/opentracing/opentracing-go/ext"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/traefik/traefik/v3/pkg/middlewares/accesslog"
"github.com/traefik/traefik/v3/pkg/tracing"
"go.opentelemetry.io/otel/trace"
)
const (
basicTypeName = "BasicAuth"
typeNameBasic = "BasicAuth"
)
type basicAuth struct {
@ -30,7 +30,7 @@ type basicAuth struct {
// NewBasic creates a basicAuth middleware.
func NewBasic(ctx context.Context, next http.Handler, authConfig dynamic.BasicAuth, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, basicTypeName).Debug().Msg("Creating middleware")
middlewares.GetLogger(ctx, name, typeNameBasic).Debug().Msg("Creating middleware")
users, err := getUsers(authConfig.UsersFile, authConfig.Users, basicUserParser)
if err != nil {
@ -55,12 +55,12 @@ func NewBasic(ctx context.Context, next http.Handler, authConfig dynamic.BasicAu
return ba, nil
}
func (b *basicAuth) GetTracingInformation() (string, ext.SpanKindEnum) {
return b.name, tracing.SpanKindNoneEnum
func (b *basicAuth) GetTracingInformation() (string, string, trace.SpanKind) {
return b.name, typeNameBasic, trace.SpanKindInternal
}
func (b *basicAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := middlewares.GetLogger(req.Context(), b.name, basicTypeName)
logger := middlewares.GetLogger(req.Context(), b.name, typeNameBasic)
user, password, ok := req.BasicAuth()
if ok {
@ -77,7 +77,7 @@ func (b *basicAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if !ok {
logger.Debug().Msg("Authentication failed")
tracing.SetErrorWithEvent(req, "Authentication failed")
tracing.SetStatusErrorf(req.Context(), "Authentication failed")
b.auth.RequireAuth(rw, req)
return

View file

@ -8,15 +8,15 @@ import (
"strings"
goauth "github.com/abbot/go-http-auth"
"github.com/opentracing/opentracing-go/ext"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/traefik/traefik/v3/pkg/middlewares/accesslog"
"github.com/traefik/traefik/v3/pkg/tracing"
"go.opentelemetry.io/otel/trace"
)
const (
digestTypeName = "digestAuth"
typeNameDigest = "digestAuth"
)
type digestAuth struct {
@ -30,7 +30,7 @@ type digestAuth struct {
// NewDigest creates a digest auth middleware.
func NewDigest(ctx context.Context, next http.Handler, authConfig dynamic.DigestAuth, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, digestTypeName).Debug().Msg("Creating middleware")
middlewares.GetLogger(ctx, name, typeNameDigest).Debug().Msg("Creating middleware")
users, err := getUsers(authConfig.UsersFile, authConfig.Users, digestUserParser)
if err != nil {
@ -54,12 +54,12 @@ func NewDigest(ctx context.Context, next http.Handler, authConfig dynamic.Digest
return da, nil
}
func (d *digestAuth) GetTracingInformation() (string, ext.SpanKindEnum) {
return d.name, tracing.SpanKindNoneEnum
func (d *digestAuth) GetTracingInformation() (string, string, trace.SpanKind) {
return d.name, typeNameDigest, trace.SpanKindInternal
}
func (d *digestAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := middlewares.GetLogger(req.Context(), d.name, digestTypeName)
logger := middlewares.GetLogger(req.Context(), d.name, typeNameDigest)
username, authinfo := d.auth.CheckAuth(req)
if username == "" {
@ -78,13 +78,13 @@ func (d *digestAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if authinfo != nil && *authinfo == "stale" {
logger.Debug().Msg("Digest authentication failed, possibly because out of order requests")
tracing.SetErrorWithEvent(req, "Digest authentication failed, possibly because out of order requests")
tracing.SetStatusErrorf(req.Context(), "Digest authentication failed, possibly because out of order requests")
d.auth.RequireAuthStale(rw, req)
return
}
logger.Debug().Msg("Digest authentication failed")
tracing.SetErrorWithEvent(req, "Digest authentication failed")
tracing.SetStatusErrorf(req.Context(), "Digest authentication failed")
d.auth.RequireAuth(rw, req)
return
}

View file

@ -11,21 +11,22 @@ import (
"strings"
"time"
"github.com/opentracing/opentracing-go/ext"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/traefik/traefik/v3/pkg/middlewares/connectionheader"
"github.com/traefik/traefik/v3/pkg/tracing"
"github.com/vulcand/oxy/v2/forward"
"github.com/vulcand/oxy/v2/utils"
"go.opentelemetry.io/otel/trace"
)
const (
xForwardedURI = "X-Forwarded-Uri"
xForwardedMethod = "X-Forwarded-Method"
forwardedTypeName = "ForwardedAuthType"
xForwardedURI = "X-Forwarded-Uri"
xForwardedMethod = "X-Forwarded-Method"
)
const typeNameForward = "ForwardAuth"
// hopHeaders Hop-by-hop headers to be removed in the authentication request.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
// Proxy-Authorization header is forwarded to the authentication server (see https://tools.ietf.org/html/rfc7235#section-4.4).
@ -51,7 +52,7 @@ type forwardAuth struct {
// NewForward creates a forward auth middleware.
func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAuth, name string) (http.Handler, error) {
middlewares.GetLogger(ctx, name, forwardedTypeName).Debug().Msg("Creating middleware")
middlewares.GetLogger(ctx, name, typeNameForward).Debug().Msg("Creating middleware")
fa := &forwardAuth{
address: config.Address,
@ -89,30 +90,38 @@ func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAu
fa.authResponseHeadersRegex = re
}
return connectionheader.Remover(fa), nil
return fa, nil
}
func (fa *forwardAuth) GetTracingInformation() (string, ext.SpanKindEnum) {
return fa.name, ext.SpanKindRPCClientEnum
func (fa *forwardAuth) GetTracingInformation() (string, string, trace.SpanKind) {
return fa.name, typeNameForward, trace.SpanKindInternal
}
func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := middlewares.GetLogger(req.Context(), fa.name, forwardedTypeName)
logger := middlewares.GetLogger(req.Context(), fa.name, typeNameForward)
forwardReq, err := http.NewRequest(http.MethodGet, fa.address, nil)
tracing.LogRequest(tracing.GetSpan(req), forwardReq)
req = connectionheader.Remove(req)
forwardReq, err := http.NewRequestWithContext(req.Context(), http.MethodGet, fa.address, nil)
if err != nil {
logMessage := fmt.Sprintf("Error calling %s. Cause %s", fa.address, err)
logger.Debug().Msg(logMessage)
tracing.SetErrorWithEvent(req, logMessage)
tracing.SetStatusErrorf(req.Context(), logMessage)
rw.WriteHeader(http.StatusInternalServerError)
return
}
// Ensure tracing headers are in the request before we copy the headers to the
// forwardReq.
tracing.InjectRequestHeaders(req)
var forwardSpan trace.Span
if tracer := tracing.TracerFromContext(req.Context()); tracer != nil {
var tracingCtx context.Context
tracingCtx, forwardSpan = tracer.Start(req.Context(), "AuthRequest", trace.WithSpanKind(trace.SpanKindClient))
defer forwardSpan.End()
forwardReq = forwardReq.WithContext(tracingCtx)
tracing.InjectContextIntoCarrier(forwardReq)
tracing.LogClientRequest(forwardSpan, forwardReq)
}
writeHeader(req, forwardReq, fa.trustForwardHeader, fa.authRequestHeaders)
@ -120,7 +129,7 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if forwardErr != nil {
logMessage := fmt.Sprintf("Error calling %s. Cause: %s", fa.address, forwardErr)
logger.Debug().Msg(logMessage)
tracing.SetErrorWithEvent(req, logMessage)
tracing.SetStatusErrorf(forwardReq.Context(), logMessage)
rw.WriteHeader(http.StatusInternalServerError)
return
@ -131,12 +140,18 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if readError != nil {
logMessage := fmt.Sprintf("Error reading body %s. Cause: %s", fa.address, readError)
logger.Debug().Msg(logMessage)
tracing.SetErrorWithEvent(req, logMessage)
tracing.SetStatusErrorf(forwardReq.Context(), logMessage)
rw.WriteHeader(http.StatusInternalServerError)
return
}
// Ending the forward request span as soon as the response is handled.
// If any errors happen earlier, this span will be close by the defer instruction.
if forwardSpan != nil {
forwardSpan.End()
}
// Pass the forward response's body and selected headers if it
// didn't return a response within the range of [200, 300).
if forwardResponse.StatusCode < http.StatusOK || forwardResponse.StatusCode >= http.StatusMultipleChoices {
@ -152,7 +167,7 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if !errors.Is(err, http.ErrNoLocation) {
logMessage := fmt.Sprintf("Error reading response location header %s. Cause: %s", fa.address, err)
logger.Debug().Msg(logMessage)
tracing.SetErrorWithEvent(req, logMessage)
tracing.SetStatusErrorf(forwardReq.Context(), logMessage)
rw.WriteHeader(http.StatusInternalServerError)
return
@ -162,7 +177,7 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("Location", redirectURL.String())
}
tracing.LogResponseCode(tracing.GetSpan(req), forwardResponse.StatusCode)
tracing.LogResponseCode(forwardSpan, forwardResponse.StatusCode, trace.SpanKindClient)
rw.WriteHeader(forwardResponse.StatusCode)
if _, err = rw.Write(body); err != nil {
@ -193,6 +208,8 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
}
}
tracing.LogResponseCode(forwardSpan, forwardResponse.StatusCode, trace.SpanKindClient)
req.RequestURI = req.URL.RequestURI()
fa.next.ServeHTTP(rw, req)
}

View file

@ -8,15 +8,22 @@ import (
"net/http/httptest"
"testing"
"github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/mocktracer"
"github.com/containous/alice"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/config/static"
tracingMiddleware "github.com/traefik/traefik/v3/pkg/middlewares/tracing"
"github.com/traefik/traefik/v3/pkg/testhelpers"
"github.com/traefik/traefik/v3/pkg/tracing"
"github.com/traefik/traefik/v3/pkg/tracing/opentelemetry"
"github.com/traefik/traefik/v3/pkg/version"
"github.com/vulcand/oxy/v2/forward"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/sdk/trace/tracetest"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
)
func TestForwardAuthFail(t *testing.T) {
@ -452,8 +459,8 @@ func Test_writeHeader(t *testing.T) {
func TestForwardAuthUsesTracing(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Mockpfx-Ids-Traceid") == "" {
t.Errorf("expected Mockpfx-Ids-Traceid header to be present in request")
if r.Header.Get("Traceparent") == "" {
t.Errorf("expected Traceparent header to be present in request")
}
}))
t.Cleanup(server.Close)
@ -464,15 +471,44 @@ func TestForwardAuthUsesTracing(t *testing.T) {
Address: server.URL,
}
tracer := mocktracer.New()
opentracing.SetGlobalTracer(tracer)
exporter := tracetest.NewInMemoryExporter()
tr, _ := tracing.NewTracing("testApp", 100, &mockBackend{tracer})
next, err := NewForward(context.Background(), next, auth, "authTest")
tres, err := resource.New(context.Background(),
resource.WithAttributes(semconv.ServiceNameKey.String("traefik")),
resource.WithAttributes(semconv.ServiceVersionKey.String(version.Version)),
resource.WithFromEnv(),
resource.WithTelemetrySDK(),
)
require.NoError(t, err)
next = tracingMiddleware.NewEntryPoint(context.Background(), tr, "tracingTest", next)
tracerProvider := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithResource(tres),
sdktrace.WithBatcher(exporter),
)
otel.SetTracerProvider(tracerProvider)
config := &static.Tracing{
ServiceName: "testApp",
SampleRate: 1,
OTLP: &opentelemetry.Config{
HTTP: &opentelemetry.HTTP{
Endpoint: "http://127.0.0.1:8080",
},
},
}
tr, closer, err := tracing.NewTracing(config)
require.NoError(t, err)
t.Cleanup(func() {
_ = closer.Close()
})
next, err = NewForward(context.Background(), next, auth, "authTest")
require.NoError(t, err)
chain := alice.New(tracingMiddleware.WrapEntryPointHandler(context.Background(), tr, "tracingTest"))
next, err = chain.Then(next)
require.NoError(t, err)
ts := httptest.NewServer(next)
t.Cleanup(ts.Close)
@ -482,11 +518,3 @@ func TestForwardAuthUsesTracing(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, http.StatusOK, res.StatusCode)
}
type mockBackend struct {
opentracing.Tracer
}
func (b *mockBackend) Setup(componentName string) (opentracing.Tracer, io.Closer, error) {
return b.Tracer, io.NopCloser(nil), nil
}