Merge branch v2.9 into master
This commit is contained in:
commit
281fa25844
17 changed files with 267 additions and 95 deletions
|
@ -227,6 +227,15 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http
|
|||
core[ClientHost] = forwardedFor
|
||||
}
|
||||
|
||||
ctx := req.Context()
|
||||
capt, err := capture.FromContext(ctx)
|
||||
if err != nil {
|
||||
log.FromContext(log.With(ctx, log.Str(log.MiddlewareType, "AccessLogs"))).
|
||||
WithError(err).
|
||||
Errorf("Could not get Capture")
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(rw, reqWithDataTable)
|
||||
|
||||
if _, ok := core[ClientUsername]; !ok {
|
||||
|
@ -237,13 +246,6 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http
|
|||
headers: rw.Header().Clone(),
|
||||
}
|
||||
|
||||
ctx := req.Context()
|
||||
capt, err := capture.FromContext(ctx)
|
||||
if err != nil {
|
||||
log.FromContext(log.With(ctx, log.Str(log.MiddlewareType, "AccessLogs"))).Errorf("Could not get Capture: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
logDataTable.DownstreamResponse.status = capt.StatusCode()
|
||||
logDataTable.DownstreamResponse.size = capt.ResponseSize()
|
||||
logDataTable.Request.size = capt.RequestSize()
|
||||
|
|
|
@ -57,7 +57,7 @@ func TestLogRotation(t *testing.T) {
|
|||
})
|
||||
|
||||
chain := alice.New()
|
||||
chain = chain.Append(capture.WrapHandler(&capture.Handler{}))
|
||||
chain = chain.Append(capture.Wrap)
|
||||
chain = chain.Append(WrapHandler(logHandler))
|
||||
handler, err := chain.Then(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
|
@ -210,7 +210,7 @@ func TestLoggerHeaderFields(t *testing.T) {
|
|||
}
|
||||
|
||||
chain := alice.New()
|
||||
chain = chain.Append(capture.WrapHandler(&capture.Handler{}))
|
||||
chain = chain.Append(capture.Wrap)
|
||||
chain = chain.Append(WrapHandler(logger))
|
||||
handler, err := chain.Then(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
|
@ -784,7 +784,7 @@ func doLoggingTLSOpt(t *testing.T, config *types.AccessLog, enableTLS bool) {
|
|||
}
|
||||
|
||||
chain := alice.New()
|
||||
chain = chain.Append(capture.WrapHandler(&capture.Handler{}))
|
||||
chain = chain.Append(capture.Wrap)
|
||||
chain = chain.Append(WrapHandler(logger))
|
||||
handler, err := chain.Then(http.HandlerFunc(logWriterTestHandlerFunc))
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -3,9 +3,8 @@
|
|||
// For another middleware to get those attributes of a request/response, this middleware
|
||||
// should be added before in the middleware chain.
|
||||
//
|
||||
// handler, _ := NewHandler()
|
||||
// chain := alice.New().
|
||||
// Append(WrapHandler(handler)).
|
||||
// Append(capture.Wrap).
|
||||
// Append(myOtherMiddleware).
|
||||
// then(...)
|
||||
//
|
||||
|
@ -33,7 +32,6 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/containous/alice"
|
||||
"github.com/traefik/traefik/v2/pkg/middlewares"
|
||||
)
|
||||
|
||||
|
@ -41,62 +39,67 @@ type key string
|
|||
|
||||
const capturedData key = "capturedData"
|
||||
|
||||
// Handler will store each request data to its context.
|
||||
type Handler struct{}
|
||||
|
||||
// WrapHandler wraps capture handler into an Alice Constructor.
|
||||
func WrapHandler(handler *Handler) alice.Constructor {
|
||||
return func(next http.Handler) (http.Handler, error) {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
handler.ServeHTTP(rw, req, next)
|
||||
}), nil
|
||||
}
|
||||
// Wrap returns a new handler that inserts a Capture into the given handler.
|
||||
// It satisfies the alice.Constructor type.
|
||||
func Wrap(handler http.Handler) (http.Handler, error) {
|
||||
c := Capture{}
|
||||
return c.Reset(handler), nil
|
||||
}
|
||||
|
||||
func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http.Handler) {
|
||||
c := Capture{}
|
||||
if req.Body != nil {
|
||||
readCounter := &readCounter{source: req.Body}
|
||||
c.rr = readCounter
|
||||
req.Body = readCounter
|
||||
// FromContext returns the Capture value found in ctx, or an empty Capture otherwise.
|
||||
func FromContext(ctx context.Context) (Capture, error) {
|
||||
c := ctx.Value(capturedData)
|
||||
if c == nil {
|
||||
return Capture{}, errors.New("value not found in context")
|
||||
}
|
||||
responseWriter := newResponseWriter(rw)
|
||||
c.rw = responseWriter
|
||||
ctx := context.WithValue(req.Context(), capturedData, &c)
|
||||
next.ServeHTTP(responseWriter, req.WithContext(ctx))
|
||||
capt, ok := c.(*Capture)
|
||||
if !ok {
|
||||
return Capture{}, errors.New("value stored in context is not a *Capture")
|
||||
}
|
||||
return *capt, nil
|
||||
}
|
||||
|
||||
// Capture is the object populated by the capture middleware,
|
||||
// allowing to gather information about the request and response.
|
||||
// holding probes that allow to gather information about the request and response.
|
||||
type Capture struct {
|
||||
rr *readCounter
|
||||
rw responseWriter
|
||||
}
|
||||
|
||||
// FromContext returns the Capture value found in ctx, or an empty Capture otherwise.
|
||||
func FromContext(ctx context.Context) (*Capture, error) {
|
||||
c := ctx.Value(capturedData)
|
||||
if c == nil {
|
||||
return nil, errors.New("value not found")
|
||||
}
|
||||
capt, ok := c.(*Capture)
|
||||
if !ok {
|
||||
return nil, errors.New("value stored in Context is not a *Capture")
|
||||
}
|
||||
return capt, nil
|
||||
// NeedsReset returns whether the given http.ResponseWriter is the capture's probe.
|
||||
func (c *Capture) NeedsReset(rw http.ResponseWriter) bool {
|
||||
return c.rw != rw
|
||||
}
|
||||
|
||||
func (c Capture) ResponseSize() int64 {
|
||||
// Reset returns a new handler that renews the Capture's probes, and inserts
|
||||
// them when deferring to next.
|
||||
func (c *Capture) Reset(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
ctx := context.WithValue(req.Context(), capturedData, c)
|
||||
newReq := req.WithContext(ctx)
|
||||
|
||||
if newReq.Body != nil {
|
||||
readCounter := &readCounter{source: newReq.Body}
|
||||
c.rr = readCounter
|
||||
newReq.Body = readCounter
|
||||
}
|
||||
c.rw = newResponseWriter(rw)
|
||||
|
||||
next.ServeHTTP(c.rw, newReq)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Capture) ResponseSize() int64 {
|
||||
return c.rw.Size()
|
||||
}
|
||||
|
||||
func (c Capture) StatusCode() int {
|
||||
func (c *Capture) StatusCode() int {
|
||||
return c.rw.Status()
|
||||
}
|
||||
|
||||
// RequestSize returns the size of the request's body if it applies,
|
||||
// zero otherwise.
|
||||
func (c Capture) RequestSize() int64 {
|
||||
func (c *Capture) RequestSize() int64 {
|
||||
if c.rr == nil {
|
||||
return 0
|
||||
}
|
||||
|
|
|
@ -38,9 +38,8 @@ func TestCapture(t *testing.T) {
|
|||
assert.Equal(t, "bar", string(all))
|
||||
})
|
||||
|
||||
wrapped := WrapHandler(&Handler{})
|
||||
chain := alice.New()
|
||||
chain = chain.Append(wrapped)
|
||||
chain = chain.Append(Wrap)
|
||||
chain = chain.Append(wrapMiddleware)
|
||||
handlers, err := chain.Then(handler)
|
||||
require.NoError(t, err)
|
||||
|
@ -142,8 +141,7 @@ func BenchmarkCapture(b *testing.B) {
|
|||
|
||||
chain := alice.New()
|
||||
if test.capture || test.body {
|
||||
captureWrapped := WrapHandler(&Handler{})
|
||||
chain = chain.Append(captureWrapped)
|
||||
chain = chain.Append(Wrap)
|
||||
}
|
||||
handlers, err := chain.Then(next)
|
||||
require.NoError(b, err)
|
||||
|
|
|
@ -24,6 +24,7 @@ const (
|
|||
protoWebsocket = "websocket"
|
||||
typeName = "Metrics"
|
||||
nameEntrypoint = "metrics-entrypoint"
|
||||
nameRouter = "metrics-router"
|
||||
nameService = "metrics-service"
|
||||
)
|
||||
|
||||
|
@ -56,7 +57,7 @@ func NewEntryPointMiddleware(ctx context.Context, next http.Handler, registry me
|
|||
|
||||
// NewRouterMiddleware creates a new metrics middleware for a Router.
|
||||
func NewRouterMiddleware(ctx context.Context, next http.Handler, registry metrics.Registry, routerName string, serviceName string) http.Handler {
|
||||
log.FromContext(middlewares.GetLoggerCtx(ctx, nameEntrypoint, typeName)).Debug("Creating middleware")
|
||||
log.FromContext(middlewares.GetLoggerCtx(ctx, nameRouter, typeName)).Debug("Creating middleware")
|
||||
|
||||
return &metricsMiddleware{
|
||||
next: next,
|
||||
|
@ -125,17 +126,25 @@ func (m *metricsMiddleware) ServeHTTP(rw http.ResponseWriter, req *http.Request)
|
|||
m.reqsTLSCounter.With(tlsLabels...).Add(1)
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
|
||||
m.next.ServeHTTP(rw, req)
|
||||
|
||||
ctx := req.Context()
|
||||
|
||||
capt, err := capture.FromContext(ctx)
|
||||
if err != nil {
|
||||
log.FromContext(middlewares.GetLoggerCtx(ctx, nameEntrypoint, typeName)).Errorf("Could not get Capture: %w", err)
|
||||
for i := 0; i < len(m.baseLabels); i += 2 {
|
||||
ctx = log.With(ctx, log.Str(m.baseLabels[i], m.baseLabels[i+1]))
|
||||
}
|
||||
log.FromContext(ctx).WithError(err).Errorf("Could not get Capture")
|
||||
return
|
||||
}
|
||||
|
||||
next := m.next
|
||||
if capt.NeedsReset(rw) {
|
||||
next = capt.Reset(m.next)
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
next.ServeHTTP(rw, req)
|
||||
|
||||
labels = append(labels, "code", strconv.Itoa(capt.StatusCode()))
|
||||
m.reqDurationHistogram.With(labels...).ObserveFromStart(start)
|
||||
m.reqsCounter.With(labels...).Add(1)
|
||||
|
|
|
@ -18,16 +18,14 @@ type ChainBuilder struct {
|
|||
metricsRegistry metrics.Registry
|
||||
accessLoggerMiddleware *accesslog.Handler
|
||||
tracer *tracing.Tracing
|
||||
captureMiddleware *capture.Handler
|
||||
}
|
||||
|
||||
// NewChainBuilder Creates a new ChainBuilder.
|
||||
func NewChainBuilder(metricsRegistry metrics.Registry, accessLoggerMiddleware *accesslog.Handler, tracer *tracing.Tracing, captureMiddleware *capture.Handler) *ChainBuilder {
|
||||
func NewChainBuilder(metricsRegistry metrics.Registry, accessLoggerMiddleware *accesslog.Handler, tracer *tracing.Tracing) *ChainBuilder {
|
||||
return &ChainBuilder{
|
||||
metricsRegistry: metricsRegistry,
|
||||
accessLoggerMiddleware: accessLoggerMiddleware,
|
||||
tracer: tracer,
|
||||
captureMiddleware: captureMiddleware,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,8 +33,8 @@ func NewChainBuilder(metricsRegistry metrics.Registry, accessLoggerMiddleware *a
|
|||
func (c *ChainBuilder) Build(ctx context.Context, entryPointName string) alice.Chain {
|
||||
chain := alice.New()
|
||||
|
||||
if c.captureMiddleware != nil {
|
||||
chain = chain.Append(capture.WrapHandler(c.captureMiddleware))
|
||||
if c.accessLoggerMiddleware != nil || c.metricsRegistry != nil && (c.metricsRegistry.IsEpEnabled() || c.metricsRegistry.IsRouterEnabled() || c.metricsRegistry.IsSvcEnabled()) {
|
||||
chain = chain.Append(capture.Wrap)
|
||||
}
|
||||
|
||||
if c.accessLoggerMiddleware != nil {
|
||||
|
|
|
@ -316,7 +316,7 @@ func TestRouterManager_Get(t *testing.T) {
|
|||
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
||||
serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager)
|
||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
||||
chainBuilder := middleware.NewChainBuilder(nil, nil, nil, nil)
|
||||
chainBuilder := middleware.NewChainBuilder(nil, nil, nil)
|
||||
|
||||
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder, metrics.NewVoidRegistry())
|
||||
|
||||
|
@ -422,7 +422,7 @@ func TestAccessLog(t *testing.T) {
|
|||
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
||||
serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager)
|
||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
||||
chainBuilder := middleware.NewChainBuilder(nil, nil, nil, nil)
|
||||
chainBuilder := middleware.NewChainBuilder(nil, nil, nil)
|
||||
|
||||
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder, metrics.NewVoidRegistry())
|
||||
|
||||
|
@ -439,7 +439,7 @@ func TestAccessLog(t *testing.T) {
|
|||
reqHost := requestdecorator.New(nil)
|
||||
|
||||
chain := alice.New()
|
||||
chain = chain.Append(capture.WrapHandler(&capture.Handler{}))
|
||||
chain = chain.Append(capture.Wrap)
|
||||
chain = chain.Append(accesslog.WrapHandler(accesslogger))
|
||||
handler, err := chain.Then(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
reqHost.ServeHTTP(w, req, handlers["web"].ServeHTTP)
|
||||
|
@ -717,7 +717,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
|||
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
||||
serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager)
|
||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
||||
chainBuilder := middleware.NewChainBuilder(nil, nil, nil, nil)
|
||||
chainBuilder := middleware.NewChainBuilder(nil, nil, nil)
|
||||
|
||||
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder, metrics.NewVoidRegistry())
|
||||
|
||||
|
@ -792,7 +792,7 @@ func TestProviderOnMiddlewares(t *testing.T) {
|
|||
roundTripperManager.Update(map[string]*dynamic.ServersTransport{"default@internal": {}})
|
||||
serviceManager := service.NewManager(rtConf.Services, nil, nil, roundTripperManager)
|
||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
||||
chainBuilder := middleware.NewChainBuilder(nil, nil, nil, nil)
|
||||
chainBuilder := middleware.NewChainBuilder(nil, nil, nil)
|
||||
|
||||
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder, metrics.NewVoidRegistry())
|
||||
|
||||
|
@ -860,7 +860,7 @@ func BenchmarkRouterServe(b *testing.B) {
|
|||
|
||||
serviceManager := service.NewManager(rtConf.Services, nil, nil, staticRoundTripperGetter{res})
|
||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager, nil)
|
||||
chainBuilder := middleware.NewChainBuilder(nil, nil, nil, nil)
|
||||
chainBuilder := middleware.NewChainBuilder(nil, nil, nil)
|
||||
|
||||
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, chainBuilder, metrics.NewVoidRegistry())
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ func TestReuseService(t *testing.T) {
|
|||
managerFactory := service.NewManagerFactory(staticConfig, nil, metrics.NewVoidRegistry(), roundTripperManager, nil)
|
||||
tlsManager := tls.NewManager()
|
||||
|
||||
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, middleware.NewChainBuilder(nil, nil, nil, nil), nil, metrics.NewVoidRegistry())
|
||||
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, middleware.NewChainBuilder(nil, nil, nil), nil, metrics.NewVoidRegistry())
|
||||
|
||||
entryPointsHandlers, _ := factory.CreateRouters(runtime.NewConfig(dynamic.Configuration{HTTP: dynamicConfigs}))
|
||||
|
||||
|
@ -189,7 +189,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
|||
managerFactory := service.NewManagerFactory(staticConfig, nil, metrics.NewVoidRegistry(), roundTripperManager, nil)
|
||||
tlsManager := tls.NewManager()
|
||||
|
||||
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, middleware.NewChainBuilder(nil, nil, nil, nil), nil, metrics.NewVoidRegistry())
|
||||
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, middleware.NewChainBuilder(nil, nil, nil), nil, metrics.NewVoidRegistry())
|
||||
|
||||
entryPointsHandlers, _ := factory.CreateRouters(runtime.NewConfig(dynamic.Configuration{HTTP: test.config(testServer.URL)}))
|
||||
|
||||
|
@ -232,7 +232,7 @@ func TestInternalServices(t *testing.T) {
|
|||
|
||||
voidRegistry := metrics.NewVoidRegistry()
|
||||
|
||||
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, middleware.NewChainBuilder(voidRegistry, nil, nil, nil), nil, voidRegistry)
|
||||
factory := NewRouterFactory(staticConfig, managerFactory, tlsManager, middleware.NewChainBuilder(voidRegistry, nil, nil), nil, voidRegistry)
|
||||
|
||||
entryPointsHandlers, _ := factory.CreateRouters(runtime.NewConfig(dynamic.Configuration{HTTP: dynamicConfigs}))
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue