Kaynağa Gözat

Tracing: allow propagation with Zipkin headers (#17009)

Closes #17006
Jonathan Rockway 6 yıl önce
ebeveyn
işleme
02975256d1

+ 5 - 0
conf/defaults.ini

@@ -553,6 +553,11 @@ sampler_type = const
 # and indicates the initial sampling rate before the actual one
 # is received from the mothership
 sampler_param = 1
+# Whether or not to use Zipkin span propagation (x-b3- HTTP headers).
+zipkin_propagation = false
+# Setting this to true disables shared RPC spans.
+# Not disabling is the most common setting when using Zipkin elsewhere in your infrastructure.
+disable_shared_zipkin_spans = false
 
 #################################### External Image Storage ##############
 [external_image_storage]

+ 5 - 1
conf/sample.ini

@@ -476,6 +476,11 @@ log_queries =
 # and indicates the initial sampling rate before the actual one
 # is received from the mothership
 ;sampler_param = 1
+# Whether or not to use Zipkin propagation (x-b3- HTTP headers).
+;zipkin_propagation = false
+# Setting this to true disables shared RPC spans.
+# Not disabling is the most common setting when using Zipkin elsewhere in your infrastructure.
+;disable_shared_zipkin_spans = false
 
 #################################### Grafana.com integration  ##########################
 # Url used to import dashboards directly from Grafana.com
@@ -530,4 +535,3 @@ log_queries =
 [plugins]
 ;enable_alpha = false
 ;app_tls_skip_verify_insecure = false
-

+ 28 - 9
pkg/infra/tracing/tracing.go

@@ -2,6 +2,7 @@ package tracing
 
 import (
 	"context"
+	"fmt"
 	"io"
 	"strings"
 
@@ -11,6 +12,7 @@ import (
 
 	opentracing "github.com/opentracing/opentracing-go"
 	jaegercfg "github.com/uber/jaeger-client-go/config"
+	"github.com/uber/jaeger-client-go/zipkin"
 )
 
 func init() {
@@ -18,13 +20,15 @@ func init() {
 }
 
 type TracingService struct {
-	enabled      bool
-	address      string
-	customTags   map[string]string
-	samplerType  string
-	samplerParam float64
-	log          log.Logger
-	closer       io.Closer
+	enabled                  bool
+	address                  string
+	customTags               map[string]string
+	samplerType              string
+	samplerParam             float64
+	log                      log.Logger
+	closer                   io.Closer
+	zipkinPropagation        bool
+	disableSharedZipkinSpans bool
 
 	Cfg *setting.Cfg `inject:""`
 }
@@ -54,6 +58,8 @@ func (ts *TracingService) parseSettings() {
 	ts.customTags = splitTagSettings(section.Key("always_included_tag").MustString(""))
 	ts.samplerType = section.Key("sampler_type").MustString("")
 	ts.samplerParam = section.Key("sampler_param").MustFloat64(1)
+	ts.zipkinPropagation = section.Key("zipkin_propagation").MustBool(false)
+	ts.disableSharedZipkinSpans = section.Key("disable_shared_zipkin_spans").MustBool(false)
 }
 
 func (ts *TracingService) initGlobalTracer() error {
@@ -79,6 +85,18 @@ func (ts *TracingService) initGlobalTracer() error {
 		options = append(options, jaegercfg.Tag(tag, value))
 	}
 
+	if ts.zipkinPropagation {
+		zipkinPropagator := zipkin.NewZipkinB3HTTPHeaderPropagator()
+		options = append(options,
+			jaegercfg.Injector(opentracing.HTTPHeaders, zipkinPropagator),
+			jaegercfg.Extractor(opentracing.HTTPHeaders, zipkinPropagator),
+		)
+
+		if !ts.disableSharedZipkinSpans {
+			options = append(options, jaegercfg.ZipkinSharedRPCSpan(true))
+		}
+	}
+
 	tracer, closer, err := cfg.NewTracer(options...)
 	if err != nil {
 		return err
@@ -124,6 +142,7 @@ func (jlw *jaegerLogWrapper) Error(msg string) {
 	jlw.logger.Error(msg)
 }
 
-func (jlw *jaegerLogWrapper) Infof(msg string, args ...interface{}) {
-	jlw.logger.Info(msg, args)
+func (jlw *jaegerLogWrapper) Infof(format string, args ...interface{}) {
+	msg := fmt.Sprintf(format, args...)
+	jlw.logger.Info(msg)
 }

+ 91 - 0
vendor/github.com/uber/jaeger-client-go/zipkin/README.md

@@ -0,0 +1,91 @@
+# Zipkin compatibility features
+
+## `NewZipkinB3HTTPHeaderPropagator()`
+
+Adds support for injecting and extracting Zipkin B3 Propagation HTTP headers,
+for use with other Zipkin collectors.
+
+```go
+
+// ...
+import (
+	opentracing "github.com/opentracing/opentracing-go"
+	jaeger "github.com/uber/jaeger-client-go"
+	"github.com/uber/jaeger-client-go/zipkin"
+)
+
+func main() {
+	// ...
+
+	zipkinPropagator := zipkin.NewZipkinB3HTTPHeaderPropagator()
+	injector := jaeger.TracerOptions.Injector(opentracing.HTTPHeaders, zipkinPropagator)
+	extractor := jaeger.TracerOptions.Extractor(opentracing.HTTPHeaders, zipkinPropagator)
+
+	// Zipkin shares span ID between client and server spans; it must be enabled via the following option.
+	zipkinSharedRPCSpan := jaeger.TracerOptions.ZipkinSharedRPCSpan(true)
+
+	// create Jaeger tracer
+	tracer, closer := jaeger.NewTracer(
+		"myService",
+		mySampler, // as usual
+		myReporter // as usual
+		injector,
+		extractor,
+		zipkinSharedRPCSpan,
+	)
+
+	opentracing.SetGlobalTracer(tracer)
+
+    // continue main()
+}
+```
+
+If you'd like to follow the official guides from https://godoc.org/github.com/uber/jaeger-client-go/config#example-Configuration-InitGlobalTracer-Production, here is an example.
+
+```go
+import (
+	"time"
+
+	opentracing "github.com/opentracing/opentracing-go"
+	"github.com/uber/jaeger-client-go"
+	jaegerClientConfig "github.com/uber/jaeger-client-go/config"
+	"github.com/uber/jaeger-client-go/zipkin"
+	"github.com/uber/jaeger-client-go/log"
+	"github.com/uber/jaeger-lib/metrics"
+)
+
+func main(){
+	//...
+	
+	// Recommended configuration for production.
+	cfg := jaegercfg.Configuration{}
+	
+	// Example logger and metrics factory. Use github.com/uber/jaeger-client-go/log
+	// and github.com/uber/jaeger-lib/metrics respectively to bind to real logging and metrics
+	// frameworks.
+	jLogger := jaegerlog.StdLogger
+	jMetricsFactory := metrics.NullFactory
+	 
+	// Zipkin shares span ID between client and server spans; it must be enabled via the following option.
+	zipkinPropagator := zipkin.NewZipkinB3HTTPHeaderPropagator()
+	 
+	// Create tracer and then initialize global tracer
+	closer, err := cfg.InitGlobalTracer(
+	  serviceName,
+	  jaegercfg.Logger(jLogger),
+	  jaegercfg.Metrics(jMetricsFactory),
+	  jaegercfg.Injector(opentracing.HTTPHeaders, zipkinPropagator),
+	  jaegercfg.Extractor(opentracing.HTTPHeaders, zipkinPropagator),
+	  jaegercfg.ZipkinSharedRPCSpan(true),
+	)
+	
+	if err != nil {
+	    log.Printf("Could not initialize jaeger tracer: %s", err.Error())
+	    return
+	}
+	defer closer.Close()
+	
+	// continue main()
+}
+
+```

+ 16 - 0
vendor/github.com/uber/jaeger-client-go/zipkin/doc.go

@@ -0,0 +1,16 @@
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package zipkin comprises Zipkin functionality for Zipkin compatibility.
+package zipkin

+ 121 - 0
vendor/github.com/uber/jaeger-client-go/zipkin/propagation.go

@@ -0,0 +1,121 @@
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package zipkin
+
+import (
+	"strconv"
+	"strings"
+
+	opentracing "github.com/opentracing/opentracing-go"
+
+	"github.com/uber/jaeger-client-go"
+)
+
+// Option is a function that sets an option on Propagator
+type Option func(propagator *Propagator)
+
+// BaggagePrefix is a function that sets baggage prefix on Propagator
+func BaggagePrefix(prefix string) Option {
+	return func(propagator *Propagator) {
+		propagator.baggagePrefix = prefix
+	}
+}
+
+// Propagator is an Injector and Extractor
+type Propagator struct {
+	baggagePrefix string
+}
+
+// NewZipkinB3HTTPHeaderPropagator creates a Propagator for extracting and injecting
+// Zipkin HTTP B3 headers into SpanContexts. Baggage is by default enabled and uses prefix
+// 'baggage-'.
+func NewZipkinB3HTTPHeaderPropagator(opts ...Option) Propagator {
+	p := Propagator{baggagePrefix: "baggage-"}
+	for _, opt := range opts {
+		opt(&p)
+	}
+	return p
+}
+
+// Inject conforms to the Injector interface for decoding Zipkin HTTP B3 headers
+func (p Propagator) Inject(
+	sc jaeger.SpanContext,
+	abstractCarrier interface{},
+) error {
+	textMapWriter, ok := abstractCarrier.(opentracing.TextMapWriter)
+	if !ok {
+		return opentracing.ErrInvalidCarrier
+	}
+
+	textMapWriter.Set("x-b3-traceid", sc.TraceID().String())
+	if sc.ParentID() != 0 {
+		textMapWriter.Set("x-b3-parentspanid", strconv.FormatUint(uint64(sc.ParentID()), 16))
+	}
+	textMapWriter.Set("x-b3-spanid", strconv.FormatUint(uint64(sc.SpanID()), 16))
+	if sc.IsSampled() {
+		textMapWriter.Set("x-b3-sampled", "1")
+	} else {
+		textMapWriter.Set("x-b3-sampled", "0")
+	}
+	sc.ForeachBaggageItem(func(k, v string) bool {
+		textMapWriter.Set(p.baggagePrefix+k, v)
+		return true
+	})
+	return nil
+}
+
+// Extract conforms to the Extractor interface for encoding Zipkin HTTP B3 headers
+func (p Propagator) Extract(abstractCarrier interface{}) (jaeger.SpanContext, error) {
+	textMapReader, ok := abstractCarrier.(opentracing.TextMapReader)
+	if !ok {
+		return jaeger.SpanContext{}, opentracing.ErrInvalidCarrier
+	}
+	var traceID jaeger.TraceID
+	var spanID uint64
+	var parentID uint64
+	sampled := false
+	var baggage map[string]string
+	err := textMapReader.ForeachKey(func(rawKey, value string) error {
+		key := strings.ToLower(rawKey) // TODO not necessary for plain TextMap
+		var err error
+		if key == "x-b3-traceid" {
+			traceID, err = jaeger.TraceIDFromString(value)
+		} else if key == "x-b3-parentspanid" {
+			parentID, err = strconv.ParseUint(value, 16, 64)
+		} else if key == "x-b3-spanid" {
+			spanID, err = strconv.ParseUint(value, 16, 64)
+		} else if key == "x-b3-sampled" && (value == "1" || value == "true") {
+			sampled = true
+		} else if strings.HasPrefix(key, p.baggagePrefix) {
+			if baggage == nil {
+				baggage = make(map[string]string)
+			}
+			baggage[key[len(p.baggagePrefix):]] = value
+		}
+		return err
+	})
+
+	if err != nil {
+		return jaeger.SpanContext{}, err
+	}
+	if !traceID.IsValid() {
+		return jaeger.SpanContext{}, opentracing.ErrSpanContextNotFound
+	}
+	return jaeger.NewSpanContext(
+		traceID,
+		jaeger.SpanID(spanID),
+		jaeger.SpanID(parentID),
+		sampled, baggage), nil
+}

+ 1 - 0
vendor/modules.txt

@@ -194,6 +194,7 @@ github.com/stretchr/testify/assert
 github.com/teris-io/shortid
 # github.com/uber/jaeger-client-go v2.16.0+incompatible
 github.com/uber/jaeger-client-go/config
+github.com/uber/jaeger-client-go/zipkin
 github.com/uber/jaeger-client-go
 github.com/uber/jaeger-client-go/internal/baggage/remote
 github.com/uber/jaeger-client-go/internal/throttler/remote