diff --git a/README.md b/README.md index 8e3f22a..ab9de6d 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,10 @@ ## 功能设计 -+ 认证&鉴权`JWT`+`Casbin` [Auth](/plugin/auth) -+ 跨域支持 [CORS](/plugin/cors) -+ Metrics [Prometheus](/plugin/metrics) ++ 认证&鉴权`JWT`+`Casbin` [Auth](/pkg/plugin/wrapper/auth) ++ 跨域支持 [CORS](/pkg/plugin/wrapper/cors) ++ Metrics [Prometheus](/pkg/plugin/wrapper/metrics) ++ Trace [Opentracing](/pkg/plugin/wrapper/trace/opentracing) + REST to GRPC 转换REST调用到GRPC(HTTP[s] -> API-Gateway -> Micro Srv)[计划中...] - 高性能 - 智能路由 diff --git a/go.mod b/go.mod index eeecd2b..ee7c393 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/micro-community/api-gateway +module github.com/micro-in-cn/x-gateway go 1.13 @@ -6,6 +6,9 @@ replace github.com/gogo/protobuf v0.0.0-20190410021324-65acae22fc9 => github.com require ( github.com/casbin/casbin/v2 v2.1.1 + github.com/chzyer/logex v1.1.10 // indirect + github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect + github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/micro/cli v0.2.0 github.com/micro/go-micro v1.16.0 @@ -14,6 +17,7 @@ require ( github.com/opentracing/opentracing-go v1.1.0 github.com/prometheus/client_golang v1.2.1 github.com/rs/cors v1.7.0 + github.com/stretchr/testify v1.4.0 github.com/uber/jaeger-client-go v2.20.1+incompatible github.com/uber/jaeger-lib v2.2.0+incompatible golang.org/x/time v0.0.0-20191024005414-555d28b269f0 diff --git a/plugin/README.md b/pkg/plugin/README.md similarity index 100% rename from plugin/README.md rename to pkg/plugin/README.md diff --git a/plugin/auth/README.md b/pkg/plugin/wrapper/auth/README.md similarity index 100% rename from plugin/auth/README.md rename to pkg/plugin/wrapper/auth/README.md diff --git a/plugin/auth/auth.go b/pkg/plugin/wrapper/auth/auth.go similarity index 98% rename from plugin/auth/auth.go rename to pkg/plugin/wrapper/auth/auth.go index 91d100e..5b3c793 100644 --- a/plugin/auth/auth.go +++ b/pkg/plugin/wrapper/auth/auth.go @@ -16,7 +16,7 @@ import ( "github.com/micro/micro/plugin" ) -const id = "hb-go.micro-plugins.micro.auth" +const id = "micro.x-gateway.auth" var adapters map[string]persist.Adapter var watchers map[string]persist.Watcher diff --git a/plugin/auth/conf/auth_key b/pkg/plugin/wrapper/auth/conf/auth_key similarity index 100% rename from plugin/auth/conf/auth_key rename to pkg/plugin/wrapper/auth/conf/auth_key diff --git a/plugin/auth/conf/auth_key.pub b/pkg/plugin/wrapper/auth/conf/auth_key.pub similarity index 100% rename from plugin/auth/conf/auth_key.pub rename to pkg/plugin/wrapper/auth/conf/auth_key.pub diff --git a/plugin/auth/conf/casbin_model.conf b/pkg/plugin/wrapper/auth/conf/casbin_model.conf similarity index 100% rename from plugin/auth/conf/casbin_model.conf rename to pkg/plugin/wrapper/auth/conf/casbin_model.conf diff --git a/plugin/auth/conf/casbin_policy.csv b/pkg/plugin/wrapper/auth/conf/casbin_policy.csv similarity index 100% rename from plugin/auth/conf/casbin_policy.csv rename to pkg/plugin/wrapper/auth/conf/casbin_policy.csv diff --git a/plugin/auth/options.go b/pkg/plugin/wrapper/auth/options.go similarity index 81% rename from plugin/auth/options.go rename to pkg/plugin/wrapper/auth/options.go index 128a8d7..5656f5d 100644 --- a/plugin/auth/options.go +++ b/pkg/plugin/wrapper/auth/options.go @@ -1,8 +1,8 @@ package auth import ( - "github.com/micro-community/api-gateway/plugin/util/request" - "github.com/micro-community/api-gateway/plugin/util/response" + "github.com/micro-in-cn/x-gateway/pkg/plugin/wrapper/util/request" + "github.com/micro-in-cn/x-gateway/pkg/plugin/wrapper/util/response" ) type Options struct { diff --git a/plugin/cors/cors.go b/pkg/plugin/wrapper/cors/cors.go similarity index 100% rename from plugin/cors/cors.go rename to pkg/plugin/wrapper/cors/cors.go diff --git a/plugin/cors/options.go b/pkg/plugin/wrapper/cors/options.go similarity index 100% rename from plugin/cors/options.go rename to pkg/plugin/wrapper/cors/options.go diff --git a/plugin/metrics/grafan.json b/pkg/plugin/wrapper/metrics/grafan.json similarity index 100% rename from plugin/metrics/grafan.json rename to pkg/plugin/wrapper/metrics/grafan.json diff --git a/plugin/metrics/metrics.go b/pkg/plugin/wrapper/metrics/metrics.go similarity index 100% rename from plugin/metrics/metrics.go rename to pkg/plugin/wrapper/metrics/metrics.go diff --git a/plugin/metrics/options.go b/pkg/plugin/wrapper/metrics/options.go similarity index 91% rename from plugin/metrics/options.go rename to pkg/plugin/wrapper/metrics/options.go index 8ca5872..72e2a16 100644 --- a/plugin/metrics/options.go +++ b/pkg/plugin/wrapper/metrics/options.go @@ -1,7 +1,7 @@ package metrics import ( - "github.com/micro-community/api-gateway/plugin/util/request" + "github.com/micro-in-cn/x-gateway/pkg/plugin/wrapper/util/request" ) type Options struct { diff --git a/plugin/metrics/prometheus.go b/pkg/plugin/wrapper/metrics/prometheus.go similarity index 96% rename from plugin/metrics/prometheus.go rename to pkg/plugin/wrapper/metrics/prometheus.go index b790ce9..a876642 100644 --- a/plugin/metrics/prometheus.go +++ b/pkg/plugin/wrapper/metrics/prometheus.go @@ -8,8 +8,8 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/micro-community/api-gateway/plugin/util/request" - "github.com/micro-community/api-gateway/plugin/util/response" + "github.com/micro-in-cn/x-gateway/pkg/plugin/wrapper/utilper/util/request" + "github.com/micro-in-cn/x-gateway/pkg/plugin/wrapper/utilper/util/response" ) var ( diff --git a/plugin/metrics/prometheus.yml b/pkg/plugin/wrapper/metrics/prometheus.yml similarity index 100% rename from plugin/metrics/prometheus.yml rename to pkg/plugin/wrapper/metrics/prometheus.yml diff --git a/pkg/plugin/wrapper/trace/opentracing/README.md b/pkg/plugin/wrapper/trace/opentracing/README.md deleted file mode 100644 index cda1faa..0000000 --- a/pkg/plugin/wrapper/trace/opentracing/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Opentracing - -Tracing仅由Gateway控制,在下游服务中仅在有Tracing时启动 diff --git a/pkg/plugin/wrapper/trace/opentracing/opentracing.go b/pkg/plugin/wrapper/trace/opentracing/opentracing.go index c2fa4b5..aeba6dd 100644 --- a/pkg/plugin/wrapper/trace/opentracing/opentracing.go +++ b/pkg/plugin/wrapper/trace/opentracing/opentracing.go @@ -1,188 +1,91 @@ -// Package opentracing provides wrappers for OpenTracing package opentracing import ( - "context" - "fmt" + "net/http" - "github.com/micro/go-micro/client" - "github.com/micro/go-micro/metadata" - "github.com/micro/go-micro/registry" - "github.com/micro/go-micro/server" + "github.com/micro/micro/plugin" "github.com/opentracing/opentracing-go" -) - -type otWrapper struct { - ot opentracing.Tracer - client.Client -} -// StartSpanFromContext returns a new span with the given operation name and options. If a span -// is found in the context, it will be used as the parent of the resulting span. -func StartSpanFromContext(ctx context.Context, tracer opentracing.Tracer, name string, opts ...opentracing.StartSpanOption) (context.Context, opentracing.Span, error) { - md, ok := metadata.FromContext(ctx) - if !ok { - md = make(map[string]string) - } + "github.com/micro-in-cn/x-gateway/pkg/plugin/wrapper/util/response" +) - // copy the metadata to prevent race - md = metadata.Copy(md) +// StartSpanFromHeader returns a new span with the given operation name and options. If a span +// is found in the header, it will be used as the parent of the resulting span. +func StartSpanFromHeader(header http.Header, tracer opentracing.Tracer, name string, opts ...opentracing.StartSpanOption) (opentracing.Span, error) { // Find parent span. - // First try to get span within current service boundary. - // If there doesn't exist, try to get it from go-micro metadata(which is cross boundary) - if parentSpan := opentracing.SpanFromContext(ctx); parentSpan != nil { - opts = append(opts, opentracing.ChildOf(parentSpan.Context())) - } else if spanCtx, err := tracer.Extract(opentracing.TextMap, opentracing.TextMapCarrier(md)); err == nil { + if spanCtx, err := tracer.Extract(opentracing.TextMap, opentracing.HTTPHeadersCarrier(header)); err == nil { opts = append(opts, opentracing.ChildOf(spanCtx)) } sp := tracer.StartSpan(name, opts...) - - if err := sp.Tracer().Inject(sp.Context(), opentracing.TextMap, opentracing.TextMapCarrier(md)); err != nil { - return nil, nil, err + if err := sp.Tracer().Inject(sp.Context(), opentracing.TextMap, opentracing.HTTPHeadersCarrier(header)); err != nil { + return nil, err } - ctx = opentracing.ContextWithSpan(ctx, sp) - ctx = metadata.NewContext(ctx, md) - return ctx, sp, nil + return sp, nil } -// SpanFromContext returns a new span with the given operation name and options. // 如果没在context中没有找到span,返回nil -func SpanFromContext(ctx context.Context, tracer opentracing.Tracer, name string, opts ...opentracing.StartSpanOption) (context.Context, opentracing.Span, error) { - md, ok := metadata.FromContext(ctx) - if !ok { - md = make(map[string]string) - } - - // copy the metadata to prevent race - md = metadata.Copy(md) +func SpanFromHeader(header http.Header, tracer opentracing.Tracer, name string, opts ...opentracing.StartSpanOption) (opentracing.Span, error) { // Find parent span. - // First try to get span within current service boundary. - // If there doesn't exist, try to get it from go-micro metadata(which is cross boundary) - if parentSpan := opentracing.SpanFromContext(ctx); parentSpan != nil { - opts = append(opts, opentracing.ChildOf(parentSpan.Context())) - } else if spanCtx, err := tracer.Extract(opentracing.TextMap, opentracing.TextMapCarrier(md)); err == nil { + if spanCtx, err := tracer.Extract(opentracing.TextMap, opentracing.HTTPHeadersCarrier(header)); err == nil { opts = append(opts, opentracing.ChildOf(spanCtx)) } else { - return ctx, nil, nil + return nil, nil } sp := tracer.StartSpan(name, opts...) - - if err := sp.Tracer().Inject(sp.Context(), opentracing.TextMap, opentracing.TextMapCarrier(md)); err != nil { - return nil, nil, err - } - - ctx = opentracing.ContextWithSpan(ctx, sp) - ctx = metadata.NewContext(ctx, md) - return ctx, sp, nil -} - -func (o *otWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { - name := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint()) - ctx, span, err := SpanFromContext(ctx, o.ot, name) - if err != nil { - return err - } else if span != nil { - defer span.Finish() - } - - return o.Client.Call(ctx, req, rsp, opts...) -} - -func (o *otWrapper) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) { - name := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint()) - ctx, span, err := SpanFromContext(ctx, o.ot, name) - if err != nil { + if err := sp.Tracer().Inject(sp.Context(), opentracing.TextMap, opentracing.HTTPHeadersCarrier(header)); err != nil { return nil, err - } else if span != nil { - defer span.Finish() - } - - return o.Client.Stream(ctx, req, opts...) -} - -func (o *otWrapper) Publish(ctx context.Context, p client.Message, opts ...client.PublishOption) error { - name := fmt.Sprintf("Pub to %s", p.Topic()) - ctx, span, err := SpanFromContext(ctx, o.ot, name) - if err != nil { - return err - } else if span != nil { - defer span.Finish() } - return o.Client.Publish(ctx, p, opts...) + return sp, nil } -// NewClientWrapper accepts an open tracing Trace and returns a Client Wrapper -func NewClientWrapper(ot opentracing.Tracer) client.Wrapper { - return func(c client.Client) client.Client { - if ot == nil { - ot = opentracing.GlobalTracer() - } - return &otWrapper{ot, c} - } +func newPlugin(opts ...Option) plugin.Plugin { + options := newOptions(opts...) + return plugin.NewPlugin( + plugin.WithName("trace"), + plugin.WithHandler(func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if options.skipperFunc(r) { + h.ServeHTTP(w, r) + return + } + + name := r.URL.Path + var span opentracing.Span + var err error + if options.autoStart { + span, err = StartSpanFromHeader(r.Header, options.tracer, name) + + } else { + span, err = SpanFromHeader(r.Header, options.tracer, name) + } + + if err != nil { + options.responseHandler(w, r, err) + return + } else if span != nil { + defer span.Finish() + + span.SetTag("http.host", r.Host) + span.SetTag("http.method", r.Method) + + ww := response.WrapWriter{ResponseWriter: w} + h.ServeHTTP(&ww, r) + + span.SetTag("http.status_code", ww.StatusCode) + } else { + h.ServeHTTP(w, r) + } + }) + }), + ) } -// NewCallWrapper accepts an opentracing Tracer and returns a Call Wrapper -func NewCallWrapper(ot opentracing.Tracer) client.CallWrapper { - return func(cf client.CallFunc) client.CallFunc { - return func(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error { - if ot == nil { - ot = opentracing.GlobalTracer() - } - name := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint()) - ctx, span, err := SpanFromContext(ctx, ot, name) - if err != nil { - return err - } else if span != nil { - defer span.Finish() - } - - return cf(ctx, node, req, rsp, opts) - } - } -} - -// NewHandlerWrapper accepts an opentracing Tracer and returns a Handler Wrapper -func NewHandlerWrapper(ot opentracing.Tracer) server.HandlerWrapper { - return func(h server.HandlerFunc) server.HandlerFunc { - return func(ctx context.Context, req server.Request, rsp interface{}) error { - if ot == nil { - ot = opentracing.GlobalTracer() - } - name := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint()) - ctx, span, err := SpanFromContext(ctx, ot, name) - if err != nil { - return err - } else if span != nil { - defer span.Finish() - } - - return h(ctx, req, rsp) - } - } -} - -// NewSubscriberWrapper accepts an opentracing Tracer and returns a Subscriber Wrapper -func NewSubscriberWrapper(ot opentracing.Tracer) server.SubscriberWrapper { - return func(next server.SubscriberFunc) server.SubscriberFunc { - return func(ctx context.Context, msg server.Message) error { - name := "Pub to " + msg.Topic() - if ot == nil { - ot = opentracing.GlobalTracer() - } - ctx, span, err := SpanFromContext(ctx, ot, name) - if err != nil { - return err - } else if span != nil { - defer span.Finish() - } - - return next(ctx, msg) - } - } +func NewPlugin(opts ...Option) plugin.Plugin { + return newPlugin(opts...) } diff --git a/pkg/plugin/wrapper/trace/opentracing/opentracing_test.go b/pkg/plugin/wrapper/trace/opentracing/opentracing_test.go deleted file mode 100644 index 6cb2e25..0000000 --- a/pkg/plugin/wrapper/trace/opentracing/opentracing_test.go +++ /dev/null @@ -1,133 +0,0 @@ -package opentracing - -import ( - "context" - "testing" - - "github.com/micro/go-micro/client" - "github.com/micro/go-micro/client/selector" - microerr "github.com/micro/go-micro/errors" - "github.com/micro/go-micro/registry/memory" - "github.com/micro/go-micro/server" - opentracing "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/mocktracer" - "github.com/stretchr/testify/assert" - - cli "github.com/micro/go-micro/client" - srv "github.com/micro/go-micro/server" -) - -type Test interface { - Method(ctx context.Context, in *TestRequest, opts ...client.CallOption) (*TestResponse, error) -} - -type TestRequest struct { - IsError bool -} -type TestResponse struct { - Message string -} - -type testHandler struct{} - -func (t *testHandler) Method(ctx context.Context, req *TestRequest, rsp *TestResponse) error { - if req.IsError { - return microerr.BadRequest("bad", "test error") - } - - rsp.Message = "passed" - - return nil -} - -func TestClient(t *testing.T) { - // setup - assert := assert.New(t) - for name, tt := range map[string]struct { - message string - isError bool - wantMessage string - wantStatus string - }{ - "OK": { - message: "passed", - isError: false, - wantMessage: "passed", - wantStatus: "OK", - }, - "Invalid": { - message: "", - isError: true, - wantMessage: "", - wantStatus: "InvalidArgument", - }, - } { - t.Run(name, func(t *testing.T) { - tracer := mocktracer.New() - - registry := memory.NewRegistry() - sel := selector.NewSelector(selector.Registry(registry)) - - serverName := "micro.server.name" - serverID := "id-1234567890" - serverVersion := "1.0.0" - - c := cli.NewClient( - client.Selector(sel), - client.WrapCall(NewCallWrapper(tracer)), - ) - - s := srv.NewServer( - server.Name(serverName), - server.Version(serverVersion), - server.Id(serverID), - server.Registry(registry), - server.WrapSubscriber(NewSubscriberWrapper(tracer)), - server.WrapHandler(NewHandlerWrapper(tracer)), - ) - defer s.Stop() - - type Test struct { - *testHandler - } - - s.Handle(s.NewHandler(&Test{new(testHandler)})) - - if err := s.Start(); err != nil { - t.Fatalf("Unexpected error starting server: %v", err) - } - - ctx, span, err := StartSpanFromContext(context.Background(), tracer, "root") - assert.NoError(err) - - req := c.NewRequest(serverName, "Test.Method", &TestRequest{IsError: tt.isError}, client.WithContentType("application/json")) - rsp := TestResponse{} - err = c.Call(ctx, req, &rsp) - - if tt.isError { - assert.Error(err) - } else { - assert.NoError(err) - } - assert.Equal(rsp.Message, tt.message) - - span.Finish() - - spans := tracer.FinishedSpans() - assert.Len(spans, 3) - - var rootSpan opentracing.Span - for _, s := range spans { - // order of traces in buffer is not garanteed - switch s.OperationName { - case "root": - rootSpan = s - } - } - - for _, s := range spans { - assert.Equal(rootSpan.Context().(mocktracer.MockSpanContext).TraceID, s.Context().(mocktracer.MockSpanContext).TraceID) - } - }) - } -} diff --git a/plugin/trace/opentracing/options.go b/pkg/plugin/wrapper/trace/opentracing/options.go similarity index 87% rename from plugin/trace/opentracing/options.go rename to pkg/plugin/wrapper/trace/opentracing/options.go index b139505..debdca9 100644 --- a/plugin/trace/opentracing/options.go +++ b/pkg/plugin/wrapper/trace/opentracing/options.go @@ -2,8 +2,9 @@ package opentracing import ( "github.com/opentracing/opentracing-go" - "github.com/micro-community/api-gateway/plugin/util/request" - "github.com/micro-community/api-gateway/plugin/util/response" + + "github.com/micro-in-cn/x-gateway/pkg/plugin/wrapper/util/request" + "github.com/micro-in-cn/x-gateway/pkg/plugin/wrapper/util/response" ) type Options struct { diff --git a/plugin/util/request/request.go b/pkg/plugin/wrapper/util/request/request.go similarity index 100% rename from plugin/util/request/request.go rename to pkg/plugin/wrapper/util/request/request.go diff --git a/plugin/util/request/skipper.go b/pkg/plugin/wrapper/util/request/skipper.go similarity index 100% rename from plugin/util/request/skipper.go rename to pkg/plugin/wrapper/util/request/skipper.go diff --git a/plugin/util/response/handler.go b/pkg/plugin/wrapper/util/response/handler.go similarity index 100% rename from plugin/util/response/handler.go rename to pkg/plugin/wrapper/util/response/handler.go diff --git a/plugin/util/response/wrap_writer.go b/pkg/plugin/wrapper/util/response/wrap_writer.go similarity index 100% rename from plugin/util/response/wrap_writer.go rename to pkg/plugin/wrapper/util/response/wrap_writer.go diff --git a/plugin.go b/plugin.go index bf8fc7a..13ab61f 100644 --- a/plugin.go +++ b/plugin.go @@ -17,12 +17,12 @@ import ( "github.com/casbin/casbin/v2/persist/file-adapter" "github.com/micro/go-micro/util/log" - "github.com/micro-community/api-gateway/plugin/auth" - "github.com/micro-community/api-gateway/plugin/cors" - "github.com/micro-community/api-gateway/plugin/metrics" - "github.com/micro-community/api-gateway/plugin/trace/opentracing" - "github.com/micro-community/api-gateway/plugin/util/response" - tracer "github.com/micro-community/api-gateway/pkg/opentracing" + tracer "github.com/micro-in-cn/x-gateway/pkg/opentracing" + "github.com/micro-in-cn/x-gateway/pkg/plugin/wrapper/auth" + "github.com/micro-in-cn/x-gateway/pkg/plugin/wrapper/cors" + "github.com/micro-in-cn/x-gateway/pkg/plugin/wrapper/metrics" + "github.com/micro-in-cn/x-gateway/pkg/plugin/wrapper/trace/opentracing" + "github.com/micro-in-cn/x-gateway/pkg/plugin/wrapper/util/response" ) var apiTracerCloser, webTracerCloser io.Closer diff --git a/plugin/trace/opentracing/opentracing.go b/plugin/trace/opentracing/opentracing.go deleted file mode 100644 index e45b22b..0000000 --- a/plugin/trace/opentracing/opentracing.go +++ /dev/null @@ -1,91 +0,0 @@ -package opentracing - -import ( - "net/http" - - "github.com/micro/micro/plugin" - "github.com/opentracing/opentracing-go" - - "github.com/micro-community/api-gateway/plugin/util/response" -) - -// StartSpanFromHeader returns a new span with the given operation name and options. If a span -// is found in the header, it will be used as the parent of the resulting span. -func StartSpanFromHeader(header http.Header, tracer opentracing.Tracer, name string, opts ...opentracing.StartSpanOption) (opentracing.Span, error) { - - // Find parent span. - if spanCtx, err := tracer.Extract(opentracing.TextMap, opentracing.HTTPHeadersCarrier(header)); err == nil { - opts = append(opts, opentracing.ChildOf(spanCtx)) - } - - sp := tracer.StartSpan(name, opts...) - if err := sp.Tracer().Inject(sp.Context(), opentracing.TextMap, opentracing.HTTPHeadersCarrier(header)); err != nil { - return nil, err - } - - return sp, nil -} - -// 如果没在context中没有找到span,返回nil -func SpanFromHeader(header http.Header, tracer opentracing.Tracer, name string, opts ...opentracing.StartSpanOption) (opentracing.Span, error) { - - // Find parent span. - if spanCtx, err := tracer.Extract(opentracing.TextMap, opentracing.HTTPHeadersCarrier(header)); err == nil { - opts = append(opts, opentracing.ChildOf(spanCtx)) - } else { - return nil, nil - } - - sp := tracer.StartSpan(name, opts...) - if err := sp.Tracer().Inject(sp.Context(), opentracing.TextMap, opentracing.HTTPHeadersCarrier(header)); err != nil { - return nil, err - } - - return sp, nil -} - -func newPlugin(opts ...Option) plugin.Plugin { - options := newOptions(opts...) - return plugin.NewPlugin( - plugin.WithName("trace"), - plugin.WithHandler(func(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if options.skipperFunc(r) { - h.ServeHTTP(w, r) - return - } - - name := r.URL.Path - var span opentracing.Span - var err error - if options.autoStart { - span, err = StartSpanFromHeader(r.Header, options.tracer, name) - - } else { - span, err = SpanFromHeader(r.Header, options.tracer, name) - } - - if err != nil { - options.responseHandler(w, r, err) - return - } else if span != nil { - defer span.Finish() - - span.SetTag("http.host", r.Host) - span.SetTag("http.method", r.Method) - - ww := response.WrapWriter{ResponseWriter: w} - h.ServeHTTP(&ww, r) - - span.SetTag("http.status_code", ww.StatusCode) - } else { - h.ServeHTTP(w, r) - } - }) - }), - ) -} - -func NewPlugin(opts ...Option) plugin.Plugin { - return newPlugin(opts...) -}