文档:https://godoc.org/github.com/opentracing/opentracing-go

函数

func GlobalTracer() Tracer

  • GlobalTracer返回全局单例“Tracer”实现
  • 在“SetGlobalTracer()”被调用之前,“GlobalTracer()”是一个noop实现,它会删除传递给它的所有数据

func SetGlobalTracer(tracer Tracer)

  • SetGlobalTracer设置了[单例]opentracing,由GlobalTracer()返回的跟踪程序
  • 在调用下面的StartSpan全局函数之前,应该在main()中尽可能早地调用SetGlobalTracer
  • 在调用“SetGlobalTracer”之前,任何通过“StartSpan”(etc)全局变量启动的span都是noops

func ContextWithSpan(ctx context.Context, span Span) context.Context

  • 返回一个新的context,它持有对span的引用
  • 如果span为nil,则返回一个没有活动span的新上下文

func StartSpan(operationName string, opts …StartSpanOption) Span

  • 创建一个span

func SpanFromContext(ctx context.Context) Span

  • SpanFromContext返回先前与’ ctx ‘关联的’ Span ‘,如果找不到,则返回’ nil


    func StartSpanFromContext(ctx context.Context, operationName string, opts …StartSpanOption) (Span, context.Context)

  • StartSpanFromContext启动并返回一个带有‘operationName’的Span,使用‘ctx’中找到的任何Span作为ChildOfRef

  • 如果找不到父节点,StartSpanFromContext创建一个根(无父节点)Span。

    1. SomeFunction(ctx context.Context, ...) {
    2. sp, ctx := opentracing.StartSpanFromContext(ctx, "SomeFunction")
    3. defer sp.Finish()
    4. ...
    5. }

    type Tracer

    Tracer是一个用于创建Span和传播SpanContext的简单、简洁的接口

    1. type Tracer interface {
    2. // Create, start, and return a new Span with the given `operationName` and
    3. // incorporate the given StartSpanOption `opts`. (Note that `opts` borrows
    4. // from the "functional options" pattern, per
    5. // http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis)
    6. //
    7. // A Span with no SpanReference options (e.g., opentracing.ChildOf() or
    8. // opentracing.FollowsFrom()) becomes the root of its own trace.
    9. //
    10. // Examples:
    11. //
    12. // var tracer opentracing.Tracer = ...
    13. //
    14. // // The root-span case:
    15. // sp := tracer.StartSpan("GetFeed")
    16. //
    17. // // The vanilla child span case:
    18. // sp := tracer.StartSpan(
    19. // "GetFeed",
    20. // opentracing.ChildOf(parentSpan.Context()))
    21. //
    22. // // All the bells and whistles:
    23. // sp := tracer.StartSpan(
    24. // "GetFeed",
    25. // opentracing.ChildOf(parentSpan.Context()),
    26. // opentracing.Tag{"user_agent", loggedReq.UserAgent},
    27. // opentracing.StartTime(loggedReq.Timestamp),
    28. // )
    29. //
    30. StartSpan(operationName string, opts ...StartSpanOption) Span
    31. // Inject() takes the `sm` SpanContext instance and injects it for
    32. // propagation within `carrier`. The actual type of `carrier` depends on
    33. // the value of `format`.
    34. //
    35. // OpenTracing defines a common set of `format` values (see BuiltinFormat),
    36. // and each has an expected carrier type.
    37. //
    38. // Other packages may declare their own `format` values, much like the keys
    39. // used by `context.Context` (see https://godoc.org/context#WithValue).
    40. //
    41. // Example usage (sans error handling):
    42. //
    43. // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
    44. // err := tracer.Inject(
    45. // span.Context(),
    46. // opentracing.HTTPHeaders,
    47. // carrier)
    48. //
    49. // NOTE: All opentracing.Tracer implementations MUST support all
    50. // BuiltinFormats.
    51. //
    52. // Implementations may return opentracing.ErrUnsupportedFormat if `format`
    53. // is not supported by (or not known by) the implementation.
    54. //
    55. // Implementations may return opentracing.ErrInvalidCarrier or any other
    56. // implementation-specific error if the format is supported but injection
    57. // fails anyway.
    58. //
    59. // See Tracer.Extract().
    60. Inject(sm SpanContext, format interface{}, carrier interface{}) error
    61. // Extract() returns a SpanContext instance given `format` and `carrier`.
    62. //
    63. // OpenTracing defines a common set of `format` values (see BuiltinFormat),
    64. // and each has an expected carrier type.
    65. //
    66. // Other packages may declare their own `format` values, much like the keys
    67. // used by `context.Context` (see
    68. // https://godoc.org/golang.org/x/net/context#WithValue).
    69. //
    70. // Example usage (with StartSpan):
    71. //
    72. //
    73. // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
    74. // clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier)
    75. //
    76. // // ... assuming the ultimate goal here is to resume the trace with a
    77. // // server-side Span:
    78. // var serverSpan opentracing.Span
    79. // if err == nil {
    80. // span = tracer.StartSpan(
    81. // rpcMethodName, ext.RPCServerOption(clientContext))
    82. // } else {
    83. // span = tracer.StartSpan(rpcMethodName)
    84. // }
    85. //
    86. //
    87. // NOTE: All opentracing.Tracer implementations MUST support all
    88. // BuiltinFormats.
    89. //
    90. // Return values:
    91. // - A successful Extract returns a SpanContext instance and a nil error
    92. // - If there was simply no SpanContext to extract in `carrier`, Extract()
    93. // returns (nil, opentracing.ErrSpanContextNotFound)
    94. // - If `format` is unsupported or unrecognized, Extract() returns (nil,
    95. // opentracing.ErrUnsupportedFormat)
    96. // - If there are more fundamental problems with the `carrier` object,
    97. // Extract() may return opentracing.ErrInvalidCarrier,
    98. // opentracing.ErrSpanContextCorrupted, or implementation-specific
    99. // errors.
    100. //
    101. // See Tracer.Inject().
    102. Extract(format interface{}, carrier interface{}) (SpanContext, error)
    103. }

    type Span

    1. type Span interface {
    2. // 设置结束时间戳并结束Span状态,每个span必须调用
    3. Finish()
    4. // 类似于Finish(),但是具有显式的控制时间戳和日志数据
    5. FinishWithOptions(opts FinishOptions)
    6. // Context() yields the SpanContext for this Span. Note that the return
    7. // value of Context() is still valid after a call to Span.Finish(), as is
    8. // a call to Span.Context() after a call to Span.Finish().
    9. Context() SpanContext
    10. // 设置或更改操作名称
    11. SetOperationName(operationName string) Span
    12. // 为span新增tag,值类型限制为numeric types, strings, or bools.
    13. SetTag(key string, value interface{}) Span
    14. // LogFields is an efficient and type-checked way to record key:value
    15. // , though the programming interface is a little
    16. // more verbose than LogKV(). Here's an example:s
    17. //
    18. // span.LogFields(
    19. // log.String("event", "soft error"),
    20. // log.String("type", "cache timeout"),
    21. // log.Int("waited.millis", 1500))
    22. //
    23. LogFields(fields ...log.Field)
    24. // LogKV is a concise, readable way to record key:value logging data about
    25. // a Span, though unfortunately this also makes it less efficient and less
    26. // type-safe than LogFields(). Here's an example:
    27. //
    28. // span.LogKV(
    29. // "event", "soft error",
    30. // "type", "cache timeout",
    31. // "waited.millis", 1500)
    32. //
    33. // For LogKV (as opposed to LogFields()), the parameters must appear as
    34. // key-value pairs, like
    35. //
    36. // span.LogKV(key1, val1, key2, val2, key3, val3, ...)
    37. //
    38. // The keys must all be strings. The values may be strings, numeric types,
    39. // bools, Go error instances, or arbitrary structs.
    40. //
    41. LogKV(alternatingKeyValues ...interface{})
    42. // SetBaggageItem在此Span及其SpanContext上设置一个键值对
    43. //它也会传播到这个Span的后代
    44. //
    45. // SetBaggageItem() enables powerful functionality given a full-stack
    46. // opentracing integration (e.g., arbitrary application data from a mobile
    47. // app can make it, transparently, all the way into the depths of a storage
    48. // system), and with it some powerful costs: use this feature with care.
    49. //
    50. // IMPORTANT NOTE #1: SetBaggageItem() will only propagate baggage items to
    51. // *future* causal descendants of the associated Span.
    52. //
    53. // IMPORTANT NOTE #2: Use this thoughtfully and with care. Every key and
    54. // value is copied into every local *and remote* child of the associated
    55. // Span, and that can add up to a lot of network and cpu overhead.
    56. //
    57. // Returns a reference to this Span for chaining.
    58. SetBaggageItem(restrictedKey, value string) Span
    59. // 根据key获取值
    60. BaggageItem(restrictedKey string) string
    61. // 返回创建此span的Tracer
    62. Tracer() Tracer
    63. }

    type SpanContext

    1. type SpanContext interface {
    2. // ForeachBaggageItem grants access to all baggage items stored in the
    3. // SpanContext.
    4. // The handler function will be called for each baggage key/value pair.
    5. // The ordering of items is not guaranteed.
    6. //
    7. // The bool return value indicates if the handler wants to continue iterating
    8. // through the rest of the baggage items; for example if the handler is trying to
    9. // find some baggage item by pattern matching the name, it can return false
    10. // as soon as the item is found to stop further iterations.
    11. ForeachBaggageItem(handler func(k, v string) bool)
    12. }

    type SpanReference

    SpanReference是一个StartSpanOption,它对一个SpanReferenceType和一个引用的SpanContext。有关支持的关系,请参阅SpanReferenceType文档。如果SpanReference是用ReferencedContext==nil创建的,那么它没有作用。因此,它允许使用更简洁的语法来启动span ```go type SpanReference struct { Type SpanReferenceType ReferencedContext SpanContext }

sc, _ := tracer.Extract(someFormat, someCarrier) span := tracer.StartSpan(“operation”, opentracing.ChildOf(sc))

  1. func ChildOf(sc [SpanContext](https://godoc.org/github.com/opentracing/opentracing-go#SpanContext)) [SpanReference](https://godoc.org/github.com/opentracing/opentracing-go#SpanReference)
  2. - 返回StartSpanOption,将新建的span作为父span(sc)的后代,如果sc == nil,则该选项无效
  3. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/344888/1598693787553-f729e133-f508-4e7f-a55e-985f62434e95.png#align=left&display=inline&height=432&margin=%5Bobject%20Object%5D&name=image.png&originHeight=432&originWidth=1600&size=46358&status=done&style=none&width=1600)<br />func FollowsFrom(sc [SpanContext](https://godoc.org/github.com/opentracing/opentracing-go#SpanContext)) [SpanReference](https://godoc.org/github.com/opentracing/opentracing-go#SpanReference)
  4. - 返回StartSpanOption,将新建的span作为父span(sc)的后代,但不直接依赖于它的结果
  5. - 如果sc == nil,则该选项无效
  6. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/344888/1598693814806-91fc0c43-6591-4f2a-b36a-3d0cf3bf44c1.png#align=left&display=inline&height=418&margin=%5Bobject%20Object%5D&name=image.png&originHeight=418&originWidth=1600&size=41691&status=done&style=none&width=1600)<br />func (r [SpanReference](https://godoc.org/github.com/opentracing/opentracing-go#SpanReference)) Apply(o *[StartSpanOptions](https://godoc.org/github.com/opentracing/opentracing-go#StartSpanOptions)) 实现StartSpanOption接口
  7. <a name="afpmu"></a>
  8. #### type [FinishOptions](https://github.com/opentracing/opentracing-go/blob/master/span.go#L134)
  9. 控制时间戳和日志数据
  10. ```go
  11. type FinishOptions struct {
  12. FinishTime time.Time
  13. LogRecords []LogRecord
  14. BulkLogData []LogData
  15. }

type StartSpanOption

  1. type StartSpanOption interface {
  2. Apply(*StartSpanOptions)
  3. }

type StartSpanOptions

  1. type StartSpanOptions struct {
  2. // Zero or more causal references to other Spans (via their SpanContext).
  3. // If empty, start a "root" Span (i.e., start a new trace).
  4. References []SpanReference
  5. // StartTime overrides the Span's start time, or implicitly becomes
  6. // time.Now() if StartTime.IsZero().
  7. StartTime time.Time
  8. // Tags may have zero or more entries; the restrictions on map values are
  9. // identical to those for Span.SetTag(). May be nil.
  10. //
  11. // If specified, the caller hands off ownership of Tags at
  12. // StartSpan() invocation time.
  13. Tags map[string]interface{}
  14. }

type Tag

tag可以作为StartSpanOption传递给新的Span添加一个标签,或者它的Set方法可以用于将标签应用到现有的Span

  1. type Tag struct {
  2. Key string
  3. Value interface{}
  4. }

func (t Tag) Apply(o *StartSpanOptions) 实现StartSpanOption接口,在开启span时可做为参数传递过去
func (t Tag) Set(s Span) 将tag应用于现有的Span

type Tags

  1. type Tags map[string]interface{}

func (t Tags) Apply(o *StartSpanOptions) 实现StartSpanOption接口,在开启span时可做为参数传递过去

type HTTPHeadersCarrier

HTTPHeadersCarrier满足了TextMapWriter 和 TextMapReader
如果多个服务都是http服务,可以直接使用HTTPHeadersCarrier作为Carrier

  1. type HTTPHeadersCarrier http.Header

Example usage for server side:

  1. carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
  2. clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier)

Example usage for client side:

  1. carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
  2. err := tracer.Inject(
  3. span.Context(),
  4. opentracing.HTTPHeaders,
  5. carrier)

func (c HTTPHeadersCarrier) ForeachKey(handler func(key, val string) error) error 满足TextMapReader interface
func (c HTTPHeadersCarrier) Set(key, val string) 满足TextMapWriter interface

type TextMapCarrier

TextMapCarrier允许使用常规的map[string]string 作为TextMapWriter 和 TextMapReader

  1. type TextMapCarrier map[string]string

func (c TextMapCarrier) ForeachKey(handler func(key, val string) error) error 满足TextMapReader interface
func (c TextMapCarrier) Set(key, val string) 满足TextMapWriter interface

type BuiltinFormat

BuiltinFormat用于划分包“opentrace”中的值,这些值将与trace . inject()和trace . extract()方法一起使用

  1. type BuiltinFormat byte
  1. const (
  2. // For Tracer.Inject(): the carrier must be an `io.Writer`.
  3. // For Tracer.Extract(): the carrier must be an `io.Reader`.
  4. Binary BuiltinFormat = iota
  5. // TextMap represents SpanContexts as key:value string pairs.
  6. // For Tracer.Inject(): the carrier must be a `TextMapWriter`.
  7. // For Tracer.Extract(): the carrier must be a `TextMapReader`.
  8. TextMap
  9. // HTTPHeaders represents SpanContexts as HTTP header string pairs.
  10. // For Tracer.Inject(): the carrier must be a `TextMapWriter`.
  11. // For Tracer.Extract(): the carrier must be a `TextMapReader`.
  12. //
  13. // See HTTPHeadersCarrier for an implementation of both TextMapWriter
  14. // and TextMapReader that defers to an http.Header instance for storage.
  15. // For example, Inject():
  16. //
  17. // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
  18. // err := span.Tracer().Inject(
  19. // span.Context(), opentracing.HTTPHeaders, carrier)
  20. //
  21. // Or Extract():
  22. //
  23. // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
  24. // clientContext, err := tracer.Extract(
  25. // opentracing.HTTPHeaders, carrier)
  26. //
  27. HTTPHeaders
  28. )

type TextMapReader

TextMapReader是TextMap内置格式的Extract()载体

  1. type TextMapReader interface {
  2. // ForeachKey returns TextMap contents via repeated calls to the `handler`
  3. // function. If any call to `handler` returns a non-nil error, ForeachKey
  4. // terminates and returns that error.
  5. //
  6. // NOTE: The backing store for the TextMapReader may contain data unrelated
  7. // to SpanContext. As such, Inject() and Extract() implementations that
  8. // call the TextMapWriter and TextMapReader interfaces must agree on a
  9. // prefix or other convention to distinguish their own key:value pairs.
  10. //
  11. // The "foreach" callback pattern reduces unnecessary copying in some cases
  12. // and also allows implementations to hold locks while the map is read.
  13. ForeachKey(handler func(key, val string) error) error
  14. }

type TextMapWriter

TextMapWriter是TextMap内置格式的Inject()载体

  1. type TextMapWriter interface {
  2. // Set a key:value pair to the carrier. Multiple calls to Set() for the
  3. // same key leads to undefined behavior.
  4. //
  5. // NOTE: The backing store for the TextMapWriter may contain data unrelated
  6. // to SpanContext. As such, Inject() and Extract() implementations that
  7. // call the TextMapWriter and TextMapReader interfaces must agree on a
  8. // prefix or other convention to distinguish their own key:value pairs.
  9. Set(key, val string)
  10. }


使用

使用context启动一个子span

  1. func xyz(ctx context.Context, ...) {
  2. ...
  3. span, ctx := opentracing.StartSpanFromContext(ctx, "operation_name")
  4. defer span.Finish()
  5. span.LogFields(
  6. log.String("event", "soft error"),
  7. log.String("type", "cache timeout"),
  8. log.Int("waited.millis", 1500))
  9. ...
  10. }
  11. 或者:
  12. func xyz(ctx context.Context, ...) {
  13. var parentCtx opentracing.SpanContext
  14. if parent := opentracing.SpanFromContext(ctx); parent != nil {
  15. parentCtx = parent.Context()
  16. }
  17. cliSpan := tracer.StartSpan(
  18. "operation_name",
  19. opentracing.ChildOf(parentCtx),
  20. opentracing.Tag{Key: string(ext.Component), Value: "gRPC"},
  21. ext.SpanKindRPCClient,
  22. )
  23. defer cliSpan.Finish()
  24. }

创建一个空trace的root节点

  1. func xyz() {
  2. ...
  3. sp := opentracing.StartSpan("operation_name")
  4. defer sp.Finish()
  5. ...
  6. }

给定父节点,创建一个子节点

  1. func xyz(parentSpan opentracing.Span, ...) {
  2. ...
  3. sp := opentracing.StartSpan(
  4. "operation_name",
  5. opentracing.ChildOf(parentSpan.Context()))
  6. defer sp.Finish()
  7. ...
  8. }

序列化到wire

  1. func makeSomeRequest(ctx context.Context) ... {
  2. if span := opentracing.SpanFromContext(ctx); span != nil {
  3. httpClient := &http.Client{}
  4. httpReq, _ := http.NewRequest("GET", "http://myservice/", nil)
  5. // Transmit the span's TraceContext as HTTP headers on our
  6. // outbound request.
  7. opentracing.GlobalTracer().Inject(
  8. span.Context(),
  9. opentracing.HTTPHeaders,
  10. opentracing.HTTPHeadersCarrier(httpReq.Header))
  11. resp, err := httpClient.Do(httpReq)
  12. ...
  13. }
  14. ...
  15. }

从wire虚拟化

  1. http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
  2. var serverSpan opentracing.Span
  3. appSpecificOperationName := ...
  4. wireContext, err := opentracing.GlobalTracer().Extract(
  5. opentracing.HTTPHeaders,
  6. opentracing.HTTPHeadersCarrier(req.Header))
  7. if err != nil {
  8. // Optionally record something about err here
  9. }
  10. // Create the span referring to the RPC client if available.
  11. // If wireContext == nil, a root span will be created.
  12. serverSpan = opentracing.StartSpan(
  13. appSpecificOperationName,
  14. ext.RPCServerOption(wireContext))
  15. defer serverSpan.Finish()
  16. ctx := opentracing.ContextWithSpan(context.Background(), serverSpan)
  17. ...
  18. }

简单例子:

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/opentracing/opentracing-go"
  6. "github.com/uber/jaeger-client-go"
  7. "github.com/uber/jaeger-client-go/config"
  8. "io"
  9. "time"
  10. )
  11. func initJaeger(service string) (opentracing.Tracer, io.Closer) {
  12. cfg := &config.Configuration{
  13. ServiceName: service,
  14. Sampler: &config.SamplerConfig{
  15. Type: "const",
  16. Param: 1,
  17. },
  18. Reporter: &config.ReporterConfig{
  19. LogSpans: true,
  20. LocalAgentHostPort: "192.168.2.45:6831",
  21. },
  22. }
  23. tracer, closer, err := cfg.NewTracer(config.Logger(jaeger.StdLogger))
  24. if err != nil {
  25. panic(fmt.Sprintf("ERROR: cannot init Jaeger: %v\n", err))
  26. }
  27. return tracer, closer
  28. }
  29. func foo3(req string, ctx context.Context) (reply string) {
  30. //1.创建子span
  31. span, _ := opentracing.StartSpanFromContext(ctx, "span_foo3")
  32. defer func() {
  33. //4.接口调用完,在tag中设置request和reply
  34. span.SetTag("request", req)
  35. span.SetTag("reply", reply)
  36. span.Finish()
  37. }()
  38. println(req)
  39. //2.模拟处理耗时
  40. time.Sleep(time.Second / 2)
  41. //3.返回reply
  42. reply = "foo3Reply"
  43. return
  44. }
  45. //跟foo3一样逻辑
  46. func foo4(req string, ctx context.Context) (reply string) {
  47. span, _ := opentracing.StartSpanFromContext(ctx, "span_foo4")
  48. defer func() {
  49. span.SetTag("request", req)
  50. span.SetTag("reply", reply)
  51. span.Finish()
  52. }()
  53. println(req)
  54. time.Sleep(time.Second / 2)
  55. reply = "foo4Reply"
  56. return
  57. }
  58. func main() {
  59. tracer, closer := initJaeger("jaeger-demo")
  60. defer closer.Close()
  61. opentracing.SetGlobalTracer(tracer) //StartspanFromContext创建新span时会用到
  62. span := tracer.StartSpan("span_root")
  63. defer span.Finish()
  64. ctx := opentracing.ContextWithSpan(context.Background(), span)
  65. r1 := foo3("Hello foo3", ctx)
  66. r2 := foo4("Hello foo4", ctx)
  67. fmt.Println(r1, r2)
  68. }

image.png
image.png
image.png