mpagenko | af80163 | 2020-07-03 10:00:42 +0000 | [diff] [blame] | 1 | package opentracing |
| 2 | |
| 3 | import "time" |
| 4 | |
| 5 | // Tracer is a simple, thin interface for Span creation and SpanContext |
| 6 | // propagation. |
| 7 | type Tracer interface { |
| 8 | |
| 9 | // Create, start, and return a new Span with the given `operationName` and |
| 10 | // incorporate the given StartSpanOption `opts`. (Note that `opts` borrows |
| 11 | // from the "functional options" pattern, per |
| 12 | // http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis) |
| 13 | // |
| 14 | // A Span with no SpanReference options (e.g., opentracing.ChildOf() or |
| 15 | // opentracing.FollowsFrom()) becomes the root of its own trace. |
| 16 | // |
| 17 | // Examples: |
| 18 | // |
| 19 | // var tracer opentracing.Tracer = ... |
| 20 | // |
| 21 | // // The root-span case: |
| 22 | // sp := tracer.StartSpan("GetFeed") |
| 23 | // |
| 24 | // // The vanilla child span case: |
| 25 | // sp := tracer.StartSpan( |
| 26 | // "GetFeed", |
| 27 | // opentracing.ChildOf(parentSpan.Context())) |
| 28 | // |
| 29 | // // All the bells and whistles: |
| 30 | // sp := tracer.StartSpan( |
| 31 | // "GetFeed", |
| 32 | // opentracing.ChildOf(parentSpan.Context()), |
| 33 | // opentracing.Tag{"user_agent", loggedReq.UserAgent}, |
| 34 | // opentracing.StartTime(loggedReq.Timestamp), |
| 35 | // ) |
| 36 | // |
| 37 | StartSpan(operationName string, opts ...StartSpanOption) Span |
| 38 | |
| 39 | // Inject() takes the `sm` SpanContext instance and injects it for |
| 40 | // propagation within `carrier`. The actual type of `carrier` depends on |
| 41 | // the value of `format`. |
| 42 | // |
| 43 | // OpenTracing defines a common set of `format` values (see BuiltinFormat), |
| 44 | // and each has an expected carrier type. |
| 45 | // |
| 46 | // Other packages may declare their own `format` values, much like the keys |
| 47 | // used by `context.Context` (see https://godoc.org/context#WithValue). |
| 48 | // |
| 49 | // Example usage (sans error handling): |
| 50 | // |
| 51 | // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) |
| 52 | // err := tracer.Inject( |
| 53 | // span.Context(), |
| 54 | // opentracing.HTTPHeaders, |
| 55 | // carrier) |
| 56 | // |
| 57 | // NOTE: All opentracing.Tracer implementations MUST support all |
| 58 | // BuiltinFormats. |
| 59 | // |
| 60 | // Implementations may return opentracing.ErrUnsupportedFormat if `format` |
| 61 | // is not supported by (or not known by) the implementation. |
| 62 | // |
| 63 | // Implementations may return opentracing.ErrInvalidCarrier or any other |
| 64 | // implementation-specific error if the format is supported but injection |
| 65 | // fails anyway. |
| 66 | // |
| 67 | // See Tracer.Extract(). |
| 68 | Inject(sm SpanContext, format interface{}, carrier interface{}) error |
| 69 | |
| 70 | // Extract() returns a SpanContext instance given `format` and `carrier`. |
| 71 | // |
| 72 | // OpenTracing defines a common set of `format` values (see BuiltinFormat), |
| 73 | // and each has an expected carrier type. |
| 74 | // |
| 75 | // Other packages may declare their own `format` values, much like the keys |
| 76 | // used by `context.Context` (see |
| 77 | // https://godoc.org/golang.org/x/net/context#WithValue). |
| 78 | // |
| 79 | // Example usage (with StartSpan): |
| 80 | // |
| 81 | // |
| 82 | // carrier := opentracing.HTTPHeadersCarrier(httpReq.Header) |
| 83 | // clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier) |
| 84 | // |
| 85 | // // ... assuming the ultimate goal here is to resume the trace with a |
| 86 | // // server-side Span: |
| 87 | // var serverSpan opentracing.Span |
| 88 | // if err == nil { |
| 89 | // span = tracer.StartSpan( |
| 90 | // rpcMethodName, ext.RPCServerOption(clientContext)) |
| 91 | // } else { |
| 92 | // span = tracer.StartSpan(rpcMethodName) |
| 93 | // } |
| 94 | // |
| 95 | // |
| 96 | // NOTE: All opentracing.Tracer implementations MUST support all |
| 97 | // BuiltinFormats. |
| 98 | // |
| 99 | // Return values: |
| 100 | // - A successful Extract returns a SpanContext instance and a nil error |
| 101 | // - If there was simply no SpanContext to extract in `carrier`, Extract() |
| 102 | // returns (nil, opentracing.ErrSpanContextNotFound) |
| 103 | // - If `format` is unsupported or unrecognized, Extract() returns (nil, |
| 104 | // opentracing.ErrUnsupportedFormat) |
| 105 | // - If there are more fundamental problems with the `carrier` object, |
| 106 | // Extract() may return opentracing.ErrInvalidCarrier, |
| 107 | // opentracing.ErrSpanContextCorrupted, or implementation-specific |
| 108 | // errors. |
| 109 | // |
| 110 | // See Tracer.Inject(). |
| 111 | Extract(format interface{}, carrier interface{}) (SpanContext, error) |
| 112 | } |
| 113 | |
| 114 | // StartSpanOptions allows Tracer.StartSpan() callers and implementors a |
| 115 | // mechanism to override the start timestamp, specify Span References, and make |
| 116 | // a single Tag or multiple Tags available at Span start time. |
| 117 | // |
| 118 | // StartSpan() callers should look at the StartSpanOption interface and |
| 119 | // implementations available in this package. |
| 120 | // |
| 121 | // Tracer implementations can convert a slice of `StartSpanOption` instances |
| 122 | // into a `StartSpanOptions` struct like so: |
| 123 | // |
| 124 | // func StartSpan(opName string, opts ...opentracing.StartSpanOption) { |
| 125 | // sso := opentracing.StartSpanOptions{} |
| 126 | // for _, o := range opts { |
| 127 | // o.Apply(&sso) |
| 128 | // } |
| 129 | // ... |
| 130 | // } |
| 131 | // |
| 132 | type StartSpanOptions struct { |
| 133 | // Zero or more causal references to other Spans (via their SpanContext). |
| 134 | // If empty, start a "root" Span (i.e., start a new trace). |
| 135 | References []SpanReference |
| 136 | |
| 137 | // StartTime overrides the Span's start time, or implicitly becomes |
| 138 | // time.Now() if StartTime.IsZero(). |
| 139 | StartTime time.Time |
| 140 | |
| 141 | // Tags may have zero or more entries; the restrictions on map values are |
| 142 | // identical to those for Span.SetTag(). May be nil. |
| 143 | // |
| 144 | // If specified, the caller hands off ownership of Tags at |
| 145 | // StartSpan() invocation time. |
| 146 | Tags map[string]interface{} |
| 147 | } |
| 148 | |
| 149 | // StartSpanOption instances (zero or more) may be passed to Tracer.StartSpan. |
| 150 | // |
| 151 | // StartSpanOption borrows from the "functional options" pattern, per |
| 152 | // http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis |
| 153 | type StartSpanOption interface { |
| 154 | Apply(*StartSpanOptions) |
| 155 | } |
| 156 | |
| 157 | // SpanReferenceType is an enum type describing different categories of |
| 158 | // relationships between two Spans. If Span-2 refers to Span-1, the |
| 159 | // SpanReferenceType describes Span-1 from Span-2's perspective. For example, |
| 160 | // ChildOfRef means that Span-1 created Span-2. |
| 161 | // |
| 162 | // NOTE: Span-1 and Span-2 do *not* necessarily depend on each other for |
| 163 | // completion; e.g., Span-2 may be part of a background job enqueued by Span-1, |
| 164 | // or Span-2 may be sitting in a distributed queue behind Span-1. |
| 165 | type SpanReferenceType int |
| 166 | |
| 167 | const ( |
| 168 | // ChildOfRef refers to a parent Span that caused *and* somehow depends |
| 169 | // upon the new child Span. Often (but not always), the parent Span cannot |
| 170 | // finish until the child Span does. |
| 171 | // |
| 172 | // An timing diagram for a ChildOfRef that's blocked on the new Span: |
| 173 | // |
| 174 | // [-Parent Span---------] |
| 175 | // [-Child Span----] |
| 176 | // |
| 177 | // See http://opentracing.io/spec/ |
| 178 | // |
| 179 | // See opentracing.ChildOf() |
| 180 | ChildOfRef SpanReferenceType = iota |
| 181 | |
| 182 | // FollowsFromRef refers to a parent Span that does not depend in any way |
| 183 | // on the result of the new child Span. For instance, one might use |
| 184 | // FollowsFromRefs to describe pipeline stages separated by queues, |
| 185 | // or a fire-and-forget cache insert at the tail end of a web request. |
| 186 | // |
| 187 | // A FollowsFromRef Span is part of the same logical trace as the new Span: |
| 188 | // i.e., the new Span is somehow caused by the work of its FollowsFromRef. |
| 189 | // |
| 190 | // All of the following could be valid timing diagrams for children that |
| 191 | // "FollowFrom" a parent. |
| 192 | // |
| 193 | // [-Parent Span-] [-Child Span-] |
| 194 | // |
| 195 | // |
| 196 | // [-Parent Span--] |
| 197 | // [-Child Span-] |
| 198 | // |
| 199 | // |
| 200 | // [-Parent Span-] |
| 201 | // [-Child Span-] |
| 202 | // |
| 203 | // See http://opentracing.io/spec/ |
| 204 | // |
| 205 | // See opentracing.FollowsFrom() |
| 206 | FollowsFromRef |
| 207 | ) |
| 208 | |
| 209 | // SpanReference is a StartSpanOption that pairs a SpanReferenceType and a |
| 210 | // referenced SpanContext. See the SpanReferenceType documentation for |
| 211 | // supported relationships. If SpanReference is created with |
| 212 | // ReferencedContext==nil, it has no effect. Thus it allows for a more concise |
| 213 | // syntax for starting spans: |
| 214 | // |
| 215 | // sc, _ := tracer.Extract(someFormat, someCarrier) |
| 216 | // span := tracer.StartSpan("operation", opentracing.ChildOf(sc)) |
| 217 | // |
| 218 | // The `ChildOf(sc)` option above will not panic if sc == nil, it will just |
| 219 | // not add the parent span reference to the options. |
| 220 | type SpanReference struct { |
| 221 | Type SpanReferenceType |
| 222 | ReferencedContext SpanContext |
| 223 | } |
| 224 | |
| 225 | // Apply satisfies the StartSpanOption interface. |
| 226 | func (r SpanReference) Apply(o *StartSpanOptions) { |
| 227 | if r.ReferencedContext != nil { |
| 228 | o.References = append(o.References, r) |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | // ChildOf returns a StartSpanOption pointing to a dependent parent span. |
| 233 | // If sc == nil, the option has no effect. |
| 234 | // |
| 235 | // See ChildOfRef, SpanReference |
| 236 | func ChildOf(sc SpanContext) SpanReference { |
| 237 | return SpanReference{ |
| 238 | Type: ChildOfRef, |
| 239 | ReferencedContext: sc, |
| 240 | } |
| 241 | } |
| 242 | |
| 243 | // FollowsFrom returns a StartSpanOption pointing to a parent Span that caused |
| 244 | // the child Span but does not directly depend on its result in any way. |
| 245 | // If sc == nil, the option has no effect. |
| 246 | // |
| 247 | // See FollowsFromRef, SpanReference |
| 248 | func FollowsFrom(sc SpanContext) SpanReference { |
| 249 | return SpanReference{ |
| 250 | Type: FollowsFromRef, |
| 251 | ReferencedContext: sc, |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | // StartTime is a StartSpanOption that sets an explicit start timestamp for the |
| 256 | // new Span. |
| 257 | type StartTime time.Time |
| 258 | |
| 259 | // Apply satisfies the StartSpanOption interface. |
| 260 | func (t StartTime) Apply(o *StartSpanOptions) { |
| 261 | o.StartTime = time.Time(t) |
| 262 | } |
| 263 | |
| 264 | // Tags are a generic map from an arbitrary string key to an opaque value type. |
| 265 | // The underlying tracing system is responsible for interpreting and |
| 266 | // serializing the values. |
| 267 | type Tags map[string]interface{} |
| 268 | |
| 269 | // Apply satisfies the StartSpanOption interface. |
| 270 | func (t Tags) Apply(o *StartSpanOptions) { |
| 271 | if o.Tags == nil { |
| 272 | o.Tags = make(map[string]interface{}) |
| 273 | } |
| 274 | for k, v := range t { |
| 275 | o.Tags[k] = v |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | // Tag may be passed as a StartSpanOption to add a tag to new spans, |
| 280 | // or its Set method may be used to apply the tag to an existing Span, |
| 281 | // for example: |
| 282 | // |
| 283 | // tracer.StartSpan("opName", Tag{"Key", value}) |
| 284 | // |
| 285 | // or |
| 286 | // |
| 287 | // Tag{"key", value}.Set(span) |
| 288 | type Tag struct { |
| 289 | Key string |
| 290 | Value interface{} |
| 291 | } |
| 292 | |
| 293 | // Apply satisfies the StartSpanOption interface. |
| 294 | func (t Tag) Apply(o *StartSpanOptions) { |
| 295 | if o.Tags == nil { |
| 296 | o.Tags = make(map[string]interface{}) |
| 297 | } |
| 298 | o.Tags[t.Key] = t.Value |
| 299 | } |
| 300 | |
| 301 | // Set applies the tag to an existing Span. |
| 302 | func (t Tag) Set(s Span) { |
| 303 | s.SetTag(t.Key, t.Value) |
| 304 | } |