Migrate to opentelemetry
This commit is contained in:
parent
45bb00be04
commit
4ddef9830b
89 changed files with 2113 additions and 3898 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue