diff options
Diffstat (limited to 'plugin/trace/trace.go')
-rw-r--r-- | plugin/trace/trace.go | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/plugin/trace/trace.go b/plugin/trace/trace.go new file mode 100644 index 000000000..fa561945e --- /dev/null +++ b/plugin/trace/trace.go @@ -0,0 +1,84 @@ +// Package trace implements OpenTracing-based tracing +package trace + +import ( + "fmt" + "sync" + "sync/atomic" + + "github.com/coredns/coredns/plugin" + // Plugin the trace package. + _ "github.com/coredns/coredns/plugin/pkg/trace" + + "github.com/miekg/dns" + ot "github.com/opentracing/opentracing-go" + zipkin "github.com/openzipkin/zipkin-go-opentracing" + "golang.org/x/net/context" +) + +type trace struct { + Next plugin.Handler + ServiceEndpoint string + Endpoint string + EndpointType string + tracer ot.Tracer + serviceName string + clientServer bool + every uint64 + count uint64 + Once sync.Once +} + +func (t *trace) Tracer() ot.Tracer { + return t.tracer +} + +// OnStartup sets up the tracer +func (t *trace) OnStartup() error { + var err error + t.Once.Do(func() { + switch t.EndpointType { + case "zipkin": + err = t.setupZipkin() + default: + err = fmt.Errorf("unknown endpoint type: %s", t.EndpointType) + } + }) + return err +} + +func (t *trace) setupZipkin() error { + + collector, err := zipkin.NewHTTPCollector(t.Endpoint) + if err != nil { + return err + } + + recorder := zipkin.NewRecorder(collector, false, t.ServiceEndpoint, t.serviceName) + t.tracer, err = zipkin.NewTracer(recorder, zipkin.ClientServerSameSpan(t.clientServer)) + + return err +} + +// Name implements the Handler interface. +func (t *trace) Name() string { + return "trace" +} + +// ServeDNS implements the plugin.Handle interface. +func (t *trace) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { + trace := false + if t.every > 0 { + queryNr := atomic.AddUint64(&t.count, 1) + + if queryNr%t.every == 0 { + trace = true + } + } + if span := ot.SpanFromContext(ctx); span == nil && trace { + span := t.Tracer().StartSpan("servedns") + defer span.Finish() + ctx = ot.ContextWithSpan(ctx, span) + } + return plugin.NextOrFailure(t.Name(), t.Next, ctx, w, r) +} |