李恒道 发表于 2023-8-12 05:14:41

opentracing Extract函数分析

看的是MockTracer的代码
在https://github.com/opentracing/opentracing-go/blob/10b1cf09e00bdc84234b8c7a4b4d4e4afe64de87/mocktracer/mocktracer.go#L110

首先根据format找到匹配的解压缩对象,调用Extract

```go
// Extract belongs to the Tracer interface.
func (t *MockTracer) Extract(format interface{}, carrier interface{}) (opentracing.SpanContext, error) {
        extractor, ok := t.extractors
        if !ok {
                return nil, opentracing.ErrUnsupportedFormat
        }
        return extractor.Extract(carrier)
}
```

我们看new生成部分

这里看到注册了两个Extractor,分别是opentracing.TextMap和opentracing.HTTPHeaders

```go
// 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(mapInjector),
                extractors:    make(mapExtractor),
        }

        // 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
}
```

而注册的代码是

可以看到是传入的第二个参数起到了作用

```go
// RegisterExtractor registers extractor for given format
func (t *MockTracer) RegisterExtractor(format interface{}, extractor Extractor) {
        t.extractors = extractor
}
```

所以我们应该看textPropagator或者httpPropagator,这里我们选择查看textPropagator
```go
textPropagator := new(TextMapPropagator)
```
这里可以看到new了一个TextMapPropagator,我们继续往下翻

可以看到Extract代码主要是将carrier断言为opentracing.TextMapReader,然后调用ForeachKey函数进行循环

```go
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(mapstring)
                        }
                        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] = safeVal
                }
                return nil
        })
        if rval.TraceID == 0 || rval.SpanID == 0 {
                return emptyContext, opentracing.ErrSpanContextNotFound
        }
        if err != nil {
                return emptyContext, err
        }
        return rval, nil
}
```

那么也就是说任何符合TextMapReader接口的都可以传入

```go
type TextMapReader interface {
        ForeachKey(handler func(key, val string) error) error
}
```

只要创造一个结构符合该接口即可调用Extract函数
页: [1]
查看完整版本: opentracing Extract函数分析