看的是MockTracer的代码
在https://github.com/opentracing/opentracing-go/blob/10b1cf09e00bdc84234b8c7a4b4d4e4afe64de87/mocktracer/mocktracer.go#L110
首先根据format找到匹配的解压缩对象,调用Extract
// Extract belongs to the Tracer interface.
func (t *MockTracer) Extract(format interface{}, carrier interface{}) (opentracing.SpanContext, error) {
extractor, ok := t.extractors[format]
if !ok {
return nil, opentracing.ErrUnsupportedFormat
}
return extractor.Extract(carrier)
}
我们看new生成部分
这里看到注册了两个Extractor,分别是opentracing.TextMap和opentracing.HTTPHeaders
// New returns a MockTracer opentracing.Tracer implementation that's intended
// to facilitate tests of OpenTracing instrumentation.
func New() *MockTracer {
t := &MockTracer{
finishedSpans: []*MockSpan{},
startedSpans: []*MockSpan{},
injectors: make(map[interface{}]Injector),
extractors: make(map[interface{}]Extractor),
}
// register default injectors/extractors
textPropagator := new(TextMapPropagator)
t.RegisterInjector(opentracing.TextMap, textPropagator)
t.RegisterExtractor(opentracing.TextMap, textPropagator)
httpPropagator := &TextMapPropagator{HTTPHeaders: true}
t.RegisterInjector(opentracing.HTTPHeaders, httpPropagator)
t.RegisterExtractor(opentracing.HTTPHeaders, httpPropagator)
return t
}
而注册的代码是
可以看到是传入的第二个参数起到了作用
// RegisterExtractor registers extractor for given format
func (t *MockTracer) RegisterExtractor(format interface{}, extractor Extractor) {
t.extractors[format] = extractor
}
所以我们应该看textPropagator或者httpPropagator,这里我们选择查看textPropagator
textPropagator := new(TextMapPropagator)
这里可以看到new了一个TextMapPropagator,我们继续往下翻
可以看到Extract代码主要是将carrier断言为opentracing.TextMapReader,然后调用ForeachKey函数进行循环
func (t *TextMapPropagator) Extract(carrier interface{}) (MockSpanContext, error) {
reader, ok := carrier.(opentracing.TextMapReader)
if !ok {
return emptyContext, opentracing.ErrInvalidCarrier
}
rval := MockSpanContext{0, 0, true, nil}
err := reader.ForeachKey(func(key, val string) error {
lowerKey := strings.ToLower(key)
switch {
case lowerKey == mockTextMapIdsPrefix+"traceid":
// Ids:
i, err := strconv.Atoi(val)
if err != nil {
return err
}
rval.TraceID = i
case lowerKey == mockTextMapIdsPrefix+"spanid":
// Ids:
i, err := strconv.Atoi(val)
if err != nil {
return err
}
rval.SpanID = i
case lowerKey == mockTextMapIdsPrefix+"sampled":
b, err := strconv.ParseBool(val)
if err != nil {
return err
}
rval.Sampled = b
case strings.HasPrefix(lowerKey, mockTextMapBaggagePrefix):
// Baggage:
if rval.Baggage == nil {
rval.Baggage = make(map[string]string)
}
safeVal := val
if t.HTTPHeaders {
// unescape errors are ignored, nothing can be done
if rawVal, err := url.QueryUnescape(val); err == nil {
safeVal = rawVal
}
}
rval.Baggage[lowerKey[len(mockTextMapBaggagePrefix):]] = safeVal
}
return nil
})
if rval.TraceID == 0 || rval.SpanID == 0 {
return emptyContext, opentracing.ErrSpanContextNotFound
}
if err != nil {
return emptyContext, err
}
return rval, nil
}
那么也就是说任何符合TextMapReader接口的都可以传入
type TextMapReader interface {
ForeachKey(handler func(key, val string) error) error
}
只要创造一个结构符合该接口即可调用Extract函数