2018-01-10 16:48:04 +00:00
|
|
|
package tracing
|
|
|
|
|
|
|
|
import (
|
2018-11-14 09:18:03 +00:00
|
|
|
"context"
|
2018-01-10 16:48:04 +00:00
|
|
|
"net/http"
|
|
|
|
|
2018-11-14 09:18:03 +00:00
|
|
|
"github.com/containous/alice"
|
|
|
|
"github.com/opentracing/opentracing-go/ext"
|
2022-11-21 17:36:05 +00:00
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
"github.com/traefik/traefik/v2/pkg/logs"
|
2020-09-16 13:46:04 +00:00
|
|
|
"github.com/traefik/traefik/v2/pkg/tracing"
|
2018-01-10 16:48:04 +00:00
|
|
|
)
|
|
|
|
|
2022-02-21 11:40:09 +00:00
|
|
|
// Traceable embeds tracing information.
|
|
|
|
type Traceable interface {
|
2018-11-14 09:18:03 +00:00
|
|
|
GetTracingInformation() (name string, spanKind ext.SpanKindEnum)
|
2018-01-10 16:48:04 +00:00
|
|
|
}
|
|
|
|
|
2022-02-21 11:40:09 +00:00
|
|
|
// Wrap adds traceability to an alice.Constructor.
|
2018-11-14 09:18:03 +00:00
|
|
|
func Wrap(ctx context.Context, constructor alice.Constructor) alice.Constructor {
|
|
|
|
return func(next http.Handler) (http.Handler, error) {
|
|
|
|
if constructor == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
handler, err := constructor(next)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2018-01-10 16:48:04 +00:00
|
|
|
}
|
|
|
|
|
2022-02-21 11:40:09 +00:00
|
|
|
if traceableHandler, ok := handler.(Traceable); ok {
|
|
|
|
name, spanKind := traceableHandler.GetTracingInformation()
|
2022-11-21 17:36:05 +00:00
|
|
|
log.Ctx(ctx).Debug().Str(logs.MiddlewareName, name).Msg("Adding tracing to middleware")
|
2018-11-14 09:18:03 +00:00
|
|
|
return NewWrapper(handler, name, spanKind), nil
|
|
|
|
}
|
|
|
|
return handler, nil
|
|
|
|
}
|
2018-06-11 09:36:03 +00:00
|
|
|
}
|
|
|
|
|
2020-05-11 10:06:07 +00:00
|
|
|
// NewWrapper returns a http.Handler struct.
|
2018-11-14 09:18:03 +00:00
|
|
|
func NewWrapper(next http.Handler, name string, spanKind ext.SpanKindEnum) http.Handler {
|
|
|
|
return &Wrapper{
|
|
|
|
next: next,
|
|
|
|
name: name,
|
|
|
|
spanKind: spanKind,
|
2018-01-10 16:48:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-14 09:18:03 +00:00
|
|
|
// Wrapper is used to wrap http handler middleware.
|
|
|
|
type Wrapper struct {
|
|
|
|
next http.Handler
|
|
|
|
name string
|
|
|
|
spanKind ext.SpanKindEnum
|
2018-06-11 09:36:03 +00:00
|
|
|
}
|
|
|
|
|
2018-11-14 09:18:03 +00:00
|
|
|
func (w *Wrapper) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|
|
|
_, err := tracing.FromContext(req.Context())
|
|
|
|
if err != nil {
|
|
|
|
w.next.ServeHTTP(rw, req)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-01-10 16:48:04 +00:00
|
|
|
var finish func()
|
2018-11-14 09:18:03 +00:00
|
|
|
_, req, finish = tracing.StartSpan(req, w.name, w.spanKind)
|
2018-01-10 16:48:04 +00:00
|
|
|
defer finish()
|
|
|
|
|
2018-11-14 09:18:03 +00:00
|
|
|
if w.next != nil {
|
|
|
|
w.next.ServeHTTP(rw, req)
|
2018-01-10 16:48:04 +00:00
|
|
|
}
|
|
|
|
}
|