- 函数
- Tracer">type Tracer
- Span">type Span
- SpanContext">type SpanContext
- SpanReference">type SpanReference
- StartSpanOption">type StartSpanOption
- StartSpanOptions">type StartSpanOptions
- Tag">type Tag
- Tags">type Tags
- HTTPHeadersCarrier">type HTTPHeadersCarrier
- TextMapCarrier">type TextMapCarrier
- BuiltinFormat">type BuiltinFormat
- TextMapReader">type TextMapReader
- TextMapWriter">type TextMapWriter
- 使用
- 简单例子:
文档: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。
SomeFunction(ctx context.Context, ...) {
sp, ctx := opentracing.StartSpanFromContext(ctx, "SomeFunction")
defer sp.Finish()
...
}
type Tracer
Tracer是一个用于创建Span和传播SpanContext的简单、简洁的接口
type Tracer interface {
// Create, start, and return a new Span with the given `operationName` and
// incorporate the given StartSpanOption `opts`. (Note that `opts` borrows
// from the "functional options" pattern, per
// http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis)
//
// A Span with no SpanReference options (e.g., opentracing.ChildOf() or
// opentracing.FollowsFrom()) becomes the root of its own trace.
//
// Examples:
//
// var tracer opentracing.Tracer = ...
//
// // The root-span case:
// sp := tracer.StartSpan("GetFeed")
//
// // The vanilla child span case:
// sp := tracer.StartSpan(
// "GetFeed",
// opentracing.ChildOf(parentSpan.Context()))
//
// // All the bells and whistles:
// sp := tracer.StartSpan(
// "GetFeed",
// opentracing.ChildOf(parentSpan.Context()),
// opentracing.Tag{"user_agent", loggedReq.UserAgent},
// opentracing.StartTime(loggedReq.Timestamp),
// )
//
StartSpan(operationName string, opts ...StartSpanOption) Span
// Inject() takes the `sm` SpanContext instance and injects it for
// propagation within `carrier`. The actual type of `carrier` depends on
// the value of `format`.
//
// OpenTracing defines a common set of `format` values (see BuiltinFormat),
// and each has an expected carrier type.
//
// Other packages may declare their own `format` values, much like the keys
// used by `context.Context` (see https://godoc.org/context#WithValue).
//
// Example usage (sans error handling):
//
// carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
// err := tracer.Inject(
// span.Context(),
// opentracing.HTTPHeaders,
// carrier)
//
// NOTE: All opentracing.Tracer implementations MUST support all
// BuiltinFormats.
//
// Implementations may return opentracing.ErrUnsupportedFormat if `format`
// is not supported by (or not known by) the implementation.
//
// Implementations may return opentracing.ErrInvalidCarrier or any other
// implementation-specific error if the format is supported but injection
// fails anyway.
//
// See Tracer.Extract().
Inject(sm SpanContext, format interface{}, carrier interface{}) error
// Extract() returns a SpanContext instance given `format` and `carrier`.
//
// OpenTracing defines a common set of `format` values (see BuiltinFormat),
// and each has an expected carrier type.
//
// Other packages may declare their own `format` values, much like the keys
// used by `context.Context` (see
// https://godoc.org/golang.org/x/net/context#WithValue).
//
// Example usage (with StartSpan):
//
//
// carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
// clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier)
//
// // ... assuming the ultimate goal here is to resume the trace with a
// // server-side Span:
// var serverSpan opentracing.Span
// if err == nil {
// span = tracer.StartSpan(
// rpcMethodName, ext.RPCServerOption(clientContext))
// } else {
// span = tracer.StartSpan(rpcMethodName)
// }
//
//
// NOTE: All opentracing.Tracer implementations MUST support all
// BuiltinFormats.
//
// Return values:
// - A successful Extract returns a SpanContext instance and a nil error
// - If there was simply no SpanContext to extract in `carrier`, Extract()
// returns (nil, opentracing.ErrSpanContextNotFound)
// - If `format` is unsupported or unrecognized, Extract() returns (nil,
// opentracing.ErrUnsupportedFormat)
// - If there are more fundamental problems with the `carrier` object,
// Extract() may return opentracing.ErrInvalidCarrier,
// opentracing.ErrSpanContextCorrupted, or implementation-specific
// errors.
//
// See Tracer.Inject().
Extract(format interface{}, carrier interface{}) (SpanContext, error)
}
type Span
type Span interface {
// 设置结束时间戳并结束Span状态,每个span必须调用
Finish()
// 类似于Finish(),但是具有显式的控制时间戳和日志数据
FinishWithOptions(opts FinishOptions)
// Context() yields the SpanContext for this Span. Note that the return
// value of Context() is still valid after a call to Span.Finish(), as is
// a call to Span.Context() after a call to Span.Finish().
Context() SpanContext
// 设置或更改操作名称
SetOperationName(operationName string) Span
// 为span新增tag,值类型限制为numeric types, strings, or bools.
SetTag(key string, value interface{}) Span
// LogFields is an efficient and type-checked way to record key:value
// , though the programming interface is a little
// more verbose than LogKV(). Here's an example:s
//
// span.LogFields(
// log.String("event", "soft error"),
// log.String("type", "cache timeout"),
// log.Int("waited.millis", 1500))
//
LogFields(fields ...log.Field)
// LogKV is a concise, readable way to record key:value logging data about
// a Span, though unfortunately this also makes it less efficient and less
// type-safe than LogFields(). Here's an example:
//
// span.LogKV(
// "event", "soft error",
// "type", "cache timeout",
// "waited.millis", 1500)
//
// For LogKV (as opposed to LogFields()), the parameters must appear as
// key-value pairs, like
//
// span.LogKV(key1, val1, key2, val2, key3, val3, ...)
//
// The keys must all be strings. The values may be strings, numeric types,
// bools, Go error instances, or arbitrary structs.
//
LogKV(alternatingKeyValues ...interface{})
// SetBaggageItem在此Span及其SpanContext上设置一个键值对
//它也会传播到这个Span的后代
//
// SetBaggageItem() enables powerful functionality given a full-stack
// opentracing integration (e.g., arbitrary application data from a mobile
// app can make it, transparently, all the way into the depths of a storage
// system), and with it some powerful costs: use this feature with care.
//
// IMPORTANT NOTE #1: SetBaggageItem() will only propagate baggage items to
// *future* causal descendants of the associated Span.
//
// IMPORTANT NOTE #2: Use this thoughtfully and with care. Every key and
// value is copied into every local *and remote* child of the associated
// Span, and that can add up to a lot of network and cpu overhead.
//
// Returns a reference to this Span for chaining.
SetBaggageItem(restrictedKey, value string) Span
// 根据key获取值
BaggageItem(restrictedKey string) string
// 返回创建此span的Tracer
Tracer() Tracer
}
type SpanContext
type SpanContext interface {
// ForeachBaggageItem grants access to all baggage items stored in the
// SpanContext.
// The handler function will be called for each baggage key/value pair.
// The ordering of items is not guaranteed.
//
// The bool return value indicates if the handler wants to continue iterating
// through the rest of the baggage items; for example if the handler is trying to
// find some baggage item by pattern matching the name, it can return false
// as soon as the item is found to stop further iterations.
ForeachBaggageItem(handler func(k, v string) bool)
}
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))
func ChildOf(sc [SpanContext](https://godoc.org/github.com/opentracing/opentracing-go#SpanContext)) [SpanReference](https://godoc.org/github.com/opentracing/opentracing-go#SpanReference)
- 返回StartSpanOption,将新建的span作为父span(sc)的后代,如果sc == nil,则该选项无效
<br />func FollowsFrom(sc [SpanContext](https://godoc.org/github.com/opentracing/opentracing-go#SpanContext)) [SpanReference](https://godoc.org/github.com/opentracing/opentracing-go#SpanReference)
- 返回StartSpanOption,将新建的span作为父span(sc)的后代,但不直接依赖于它的结果
- 如果sc == nil,则该选项无效
<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接口
<a name="afpmu"></a>
#### type [FinishOptions](https://github.com/opentracing/opentracing-go/blob/master/span.go#L134)
控制时间戳和日志数据
```go
type FinishOptions struct {
FinishTime time.Time
LogRecords []LogRecord
BulkLogData []LogData
}
type StartSpanOption
type StartSpanOption interface {
Apply(*StartSpanOptions)
}
type StartSpanOptions
type StartSpanOptions struct {
// Zero or more causal references to other Spans (via their SpanContext).
// If empty, start a "root" Span (i.e., start a new trace).
References []SpanReference
// StartTime overrides the Span's start time, or implicitly becomes
// time.Now() if StartTime.IsZero().
StartTime time.Time
// Tags may have zero or more entries; the restrictions on map values are
// identical to those for Span.SetTag(). May be nil.
//
// If specified, the caller hands off ownership of Tags at
// StartSpan() invocation time.
Tags map[string]interface{}
}
type Tag
tag可以作为StartSpanOption传递给新的Span添加一个标签,或者它的Set方法可以用于将标签应用到现有的Span
type Tag struct {
Key string
Value interface{}
}
func (t Tag) Apply(o *StartSpanOptions) 实现StartSpanOption接口,在开启span时可做为参数传递过去
func (t Tag) Set(s Span) 将tag应用于现有的Span
type Tags
type Tags map[string]interface{}
func (t Tags) Apply(o *StartSpanOptions) 实现StartSpanOption接口,在开启span时可做为参数传递过去
type HTTPHeadersCarrier
HTTPHeadersCarrier满足了TextMapWriter 和 TextMapReader
如果多个服务都是http服务,可以直接使用HTTPHeadersCarrier作为Carrier
type HTTPHeadersCarrier http.Header
Example usage for server side:
carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier)
Example usage for client side:
carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
err := tracer.Inject(
span.Context(),
opentracing.HTTPHeaders,
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
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()方法一起使用
type BuiltinFormat byte
const (
// For Tracer.Inject(): the carrier must be an `io.Writer`.
// For Tracer.Extract(): the carrier must be an `io.Reader`.
Binary BuiltinFormat = iota
// TextMap represents SpanContexts as key:value string pairs.
// For Tracer.Inject(): the carrier must be a `TextMapWriter`.
// For Tracer.Extract(): the carrier must be a `TextMapReader`.
TextMap
// HTTPHeaders represents SpanContexts as HTTP header string pairs.
// For Tracer.Inject(): the carrier must be a `TextMapWriter`.
// For Tracer.Extract(): the carrier must be a `TextMapReader`.
//
// See HTTPHeadersCarrier for an implementation of both TextMapWriter
// and TextMapReader that defers to an http.Header instance for storage.
// For example, Inject():
//
// carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
// err := span.Tracer().Inject(
// span.Context(), opentracing.HTTPHeaders, carrier)
//
// Or Extract():
//
// carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
// clientContext, err := tracer.Extract(
// opentracing.HTTPHeaders, carrier)
//
HTTPHeaders
)
type TextMapReader
TextMapReader是TextMap内置格式的Extract()载体
type TextMapReader interface {
// ForeachKey returns TextMap contents via repeated calls to the `handler`
// function. If any call to `handler` returns a non-nil error, ForeachKey
// terminates and returns that error.
//
// NOTE: The backing store for the TextMapReader may contain data unrelated
// to SpanContext. As such, Inject() and Extract() implementations that
// call the TextMapWriter and TextMapReader interfaces must agree on a
// prefix or other convention to distinguish their own key:value pairs.
//
// The "foreach" callback pattern reduces unnecessary copying in some cases
// and also allows implementations to hold locks while the map is read.
ForeachKey(handler func(key, val string) error) error
}
type TextMapWriter
TextMapWriter是TextMap内置格式的Inject()载体
type TextMapWriter interface {
// Set a key:value pair to the carrier. Multiple calls to Set() for the
// same key leads to undefined behavior.
//
// NOTE: The backing store for the TextMapWriter may contain data unrelated
// to SpanContext. As such, Inject() and Extract() implementations that
// call the TextMapWriter and TextMapReader interfaces must agree on a
// prefix or other convention to distinguish their own key:value pairs.
Set(key, val string)
}
使用
使用context启动一个子span
func xyz(ctx context.Context, ...) {
...
span, ctx := opentracing.StartSpanFromContext(ctx, "operation_name")
defer span.Finish()
span.LogFields(
log.String("event", "soft error"),
log.String("type", "cache timeout"),
log.Int("waited.millis", 1500))
...
}
或者:
func xyz(ctx context.Context, ...) {
var parentCtx opentracing.SpanContext
if parent := opentracing.SpanFromContext(ctx); parent != nil {
parentCtx = parent.Context()
}
cliSpan := tracer.StartSpan(
"operation_name",
opentracing.ChildOf(parentCtx),
opentracing.Tag{Key: string(ext.Component), Value: "gRPC"},
ext.SpanKindRPCClient,
)
defer cliSpan.Finish()
}
创建一个空trace的root节点
func xyz() {
...
sp := opentracing.StartSpan("operation_name")
defer sp.Finish()
...
}
给定父节点,创建一个子节点
func xyz(parentSpan opentracing.Span, ...) {
...
sp := opentracing.StartSpan(
"operation_name",
opentracing.ChildOf(parentSpan.Context()))
defer sp.Finish()
...
}
序列化到wire
func makeSomeRequest(ctx context.Context) ... {
if span := opentracing.SpanFromContext(ctx); span != nil {
httpClient := &http.Client{}
httpReq, _ := http.NewRequest("GET", "http://myservice/", nil)
// Transmit the span's TraceContext as HTTP headers on our
// outbound request.
opentracing.GlobalTracer().Inject(
span.Context(),
opentracing.HTTPHeaders,
opentracing.HTTPHeadersCarrier(httpReq.Header))
resp, err := httpClient.Do(httpReq)
...
}
...
}
从wire虚拟化
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
var serverSpan opentracing.Span
appSpecificOperationName := ...
wireContext, err := opentracing.GlobalTracer().Extract(
opentracing.HTTPHeaders,
opentracing.HTTPHeadersCarrier(req.Header))
if err != nil {
// Optionally record something about err here
}
// Create the span referring to the RPC client if available.
// If wireContext == nil, a root span will be created.
serverSpan = opentracing.StartSpan(
appSpecificOperationName,
ext.RPCServerOption(wireContext))
defer serverSpan.Finish()
ctx := opentracing.ContextWithSpan(context.Background(), serverSpan)
...
}
简单例子:
package main
import (
"context"
"fmt"
"github.com/opentracing/opentracing-go"
"github.com/uber/jaeger-client-go"
"github.com/uber/jaeger-client-go/config"
"io"
"time"
)
func initJaeger(service string) (opentracing.Tracer, io.Closer) {
cfg := &config.Configuration{
ServiceName: service,
Sampler: &config.SamplerConfig{
Type: "const",
Param: 1,
},
Reporter: &config.ReporterConfig{
LogSpans: true,
LocalAgentHostPort: "192.168.2.45:6831",
},
}
tracer, closer, err := cfg.NewTracer(config.Logger(jaeger.StdLogger))
if err != nil {
panic(fmt.Sprintf("ERROR: cannot init Jaeger: %v\n", err))
}
return tracer, closer
}
func foo3(req string, ctx context.Context) (reply string) {
//1.创建子span
span, _ := opentracing.StartSpanFromContext(ctx, "span_foo3")
defer func() {
//4.接口调用完,在tag中设置request和reply
span.SetTag("request", req)
span.SetTag("reply", reply)
span.Finish()
}()
println(req)
//2.模拟处理耗时
time.Sleep(time.Second / 2)
//3.返回reply
reply = "foo3Reply"
return
}
//跟foo3一样逻辑
func foo4(req string, ctx context.Context) (reply string) {
span, _ := opentracing.StartSpanFromContext(ctx, "span_foo4")
defer func() {
span.SetTag("request", req)
span.SetTag("reply", reply)
span.Finish()
}()
println(req)
time.Sleep(time.Second / 2)
reply = "foo4Reply"
return
}
func main() {
tracer, closer := initJaeger("jaeger-demo")
defer closer.Close()
opentracing.SetGlobalTracer(tracer) //StartspanFromContext创建新span时会用到
span := tracer.StartSpan("span_root")
defer span.Finish()
ctx := opentracing.ContextWithSpan(context.Background(), span)
r1 := foo3("Hello foo3", ctx)
r2 := foo4("Hello foo4", ctx)
fmt.Println(r1, r2)
}