trace.go (18663B)
1 // Copyright The OpenTelemetry Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package trace // import "go.opentelemetry.io/otel/trace" 16 17 import ( 18 "bytes" 19 "context" 20 "encoding/hex" 21 "encoding/json" 22 23 "go.opentelemetry.io/otel/attribute" 24 "go.opentelemetry.io/otel/codes" 25 ) 26 27 const ( 28 // FlagsSampled is a bitmask with the sampled bit set. A SpanContext 29 // with the sampling bit set means the span is sampled. 30 FlagsSampled = TraceFlags(0x01) 31 32 errInvalidHexID errorConst = "trace-id and span-id can only contain [0-9a-f] characters, all lowercase" 33 34 errInvalidTraceIDLength errorConst = "hex encoded trace-id must have length equals to 32" 35 errNilTraceID errorConst = "trace-id can't be all zero" 36 37 errInvalidSpanIDLength errorConst = "hex encoded span-id must have length equals to 16" 38 errNilSpanID errorConst = "span-id can't be all zero" 39 ) 40 41 type errorConst string 42 43 func (e errorConst) Error() string { 44 return string(e) 45 } 46 47 // TraceID is a unique identity of a trace. 48 // nolint:revive // revive complains about stutter of `trace.TraceID`. 49 type TraceID [16]byte 50 51 var nilTraceID TraceID 52 var _ json.Marshaler = nilTraceID 53 54 // IsValid checks whether the trace TraceID is valid. A valid trace ID does 55 // not consist of zeros only. 56 func (t TraceID) IsValid() bool { 57 return !bytes.Equal(t[:], nilTraceID[:]) 58 } 59 60 // MarshalJSON implements a custom marshal function to encode TraceID 61 // as a hex string. 62 func (t TraceID) MarshalJSON() ([]byte, error) { 63 return json.Marshal(t.String()) 64 } 65 66 // String returns the hex string representation form of a TraceID. 67 func (t TraceID) String() string { 68 return hex.EncodeToString(t[:]) 69 } 70 71 // SpanID is a unique identity of a span in a trace. 72 type SpanID [8]byte 73 74 var nilSpanID SpanID 75 var _ json.Marshaler = nilSpanID 76 77 // IsValid checks whether the SpanID is valid. A valid SpanID does not consist 78 // of zeros only. 79 func (s SpanID) IsValid() bool { 80 return !bytes.Equal(s[:], nilSpanID[:]) 81 } 82 83 // MarshalJSON implements a custom marshal function to encode SpanID 84 // as a hex string. 85 func (s SpanID) MarshalJSON() ([]byte, error) { 86 return json.Marshal(s.String()) 87 } 88 89 // String returns the hex string representation form of a SpanID. 90 func (s SpanID) String() string { 91 return hex.EncodeToString(s[:]) 92 } 93 94 // TraceIDFromHex returns a TraceID from a hex string if it is compliant with 95 // the W3C trace-context specification. See more at 96 // https://www.w3.org/TR/trace-context/#trace-id 97 // nolint:revive // revive complains about stutter of `trace.TraceIDFromHex`. 98 func TraceIDFromHex(h string) (TraceID, error) { 99 t := TraceID{} 100 if len(h) != 32 { 101 return t, errInvalidTraceIDLength 102 } 103 104 if err := decodeHex(h, t[:]); err != nil { 105 return t, err 106 } 107 108 if !t.IsValid() { 109 return t, errNilTraceID 110 } 111 return t, nil 112 } 113 114 // SpanIDFromHex returns a SpanID from a hex string if it is compliant 115 // with the w3c trace-context specification. 116 // See more at https://www.w3.org/TR/trace-context/#parent-id 117 func SpanIDFromHex(h string) (SpanID, error) { 118 s := SpanID{} 119 if len(h) != 16 { 120 return s, errInvalidSpanIDLength 121 } 122 123 if err := decodeHex(h, s[:]); err != nil { 124 return s, err 125 } 126 127 if !s.IsValid() { 128 return s, errNilSpanID 129 } 130 return s, nil 131 } 132 133 func decodeHex(h string, b []byte) error { 134 for _, r := range h { 135 switch { 136 case 'a' <= r && r <= 'f': 137 continue 138 case '0' <= r && r <= '9': 139 continue 140 default: 141 return errInvalidHexID 142 } 143 } 144 145 decoded, err := hex.DecodeString(h) 146 if err != nil { 147 return err 148 } 149 150 copy(b, decoded) 151 return nil 152 } 153 154 // TraceFlags contains flags that can be set on a SpanContext. 155 type TraceFlags byte //nolint:revive // revive complains about stutter of `trace.TraceFlags`. 156 157 // IsSampled returns if the sampling bit is set in the TraceFlags. 158 func (tf TraceFlags) IsSampled() bool { 159 return tf&FlagsSampled == FlagsSampled 160 } 161 162 // WithSampled sets the sampling bit in a new copy of the TraceFlags. 163 func (tf TraceFlags) WithSampled(sampled bool) TraceFlags { // nolint:revive // sampled is not a control flag. 164 if sampled { 165 return tf | FlagsSampled 166 } 167 168 return tf &^ FlagsSampled 169 } 170 171 // MarshalJSON implements a custom marshal function to encode TraceFlags 172 // as a hex string. 173 func (tf TraceFlags) MarshalJSON() ([]byte, error) { 174 return json.Marshal(tf.String()) 175 } 176 177 // String returns the hex string representation form of TraceFlags. 178 func (tf TraceFlags) String() string { 179 return hex.EncodeToString([]byte{byte(tf)}[:]) 180 } 181 182 // SpanContextConfig contains mutable fields usable for constructing 183 // an immutable SpanContext. 184 type SpanContextConfig struct { 185 TraceID TraceID 186 SpanID SpanID 187 TraceFlags TraceFlags 188 TraceState TraceState 189 Remote bool 190 } 191 192 // NewSpanContext constructs a SpanContext using values from the provided 193 // SpanContextConfig. 194 func NewSpanContext(config SpanContextConfig) SpanContext { 195 return SpanContext{ 196 traceID: config.TraceID, 197 spanID: config.SpanID, 198 traceFlags: config.TraceFlags, 199 traceState: config.TraceState, 200 remote: config.Remote, 201 } 202 } 203 204 // SpanContext contains identifying trace information about a Span. 205 type SpanContext struct { 206 traceID TraceID 207 spanID SpanID 208 traceFlags TraceFlags 209 traceState TraceState 210 remote bool 211 } 212 213 var _ json.Marshaler = SpanContext{} 214 215 // IsValid returns if the SpanContext is valid. A valid span context has a 216 // valid TraceID and SpanID. 217 func (sc SpanContext) IsValid() bool { 218 return sc.HasTraceID() && sc.HasSpanID() 219 } 220 221 // IsRemote indicates whether the SpanContext represents a remotely-created Span. 222 func (sc SpanContext) IsRemote() bool { 223 return sc.remote 224 } 225 226 // WithRemote returns a copy of sc with the Remote property set to remote. 227 func (sc SpanContext) WithRemote(remote bool) SpanContext { 228 return SpanContext{ 229 traceID: sc.traceID, 230 spanID: sc.spanID, 231 traceFlags: sc.traceFlags, 232 traceState: sc.traceState, 233 remote: remote, 234 } 235 } 236 237 // TraceID returns the TraceID from the SpanContext. 238 func (sc SpanContext) TraceID() TraceID { 239 return sc.traceID 240 } 241 242 // HasTraceID checks if the SpanContext has a valid TraceID. 243 func (sc SpanContext) HasTraceID() bool { 244 return sc.traceID.IsValid() 245 } 246 247 // WithTraceID returns a new SpanContext with the TraceID replaced. 248 func (sc SpanContext) WithTraceID(traceID TraceID) SpanContext { 249 return SpanContext{ 250 traceID: traceID, 251 spanID: sc.spanID, 252 traceFlags: sc.traceFlags, 253 traceState: sc.traceState, 254 remote: sc.remote, 255 } 256 } 257 258 // SpanID returns the SpanID from the SpanContext. 259 func (sc SpanContext) SpanID() SpanID { 260 return sc.spanID 261 } 262 263 // HasSpanID checks if the SpanContext has a valid SpanID. 264 func (sc SpanContext) HasSpanID() bool { 265 return sc.spanID.IsValid() 266 } 267 268 // WithSpanID returns a new SpanContext with the SpanID replaced. 269 func (sc SpanContext) WithSpanID(spanID SpanID) SpanContext { 270 return SpanContext{ 271 traceID: sc.traceID, 272 spanID: spanID, 273 traceFlags: sc.traceFlags, 274 traceState: sc.traceState, 275 remote: sc.remote, 276 } 277 } 278 279 // TraceFlags returns the flags from the SpanContext. 280 func (sc SpanContext) TraceFlags() TraceFlags { 281 return sc.traceFlags 282 } 283 284 // IsSampled returns if the sampling bit is set in the SpanContext's TraceFlags. 285 func (sc SpanContext) IsSampled() bool { 286 return sc.traceFlags.IsSampled() 287 } 288 289 // WithTraceFlags returns a new SpanContext with the TraceFlags replaced. 290 func (sc SpanContext) WithTraceFlags(flags TraceFlags) SpanContext { 291 return SpanContext{ 292 traceID: sc.traceID, 293 spanID: sc.spanID, 294 traceFlags: flags, 295 traceState: sc.traceState, 296 remote: sc.remote, 297 } 298 } 299 300 // TraceState returns the TraceState from the SpanContext. 301 func (sc SpanContext) TraceState() TraceState { 302 return sc.traceState 303 } 304 305 // WithTraceState returns a new SpanContext with the TraceState replaced. 306 func (sc SpanContext) WithTraceState(state TraceState) SpanContext { 307 return SpanContext{ 308 traceID: sc.traceID, 309 spanID: sc.spanID, 310 traceFlags: sc.traceFlags, 311 traceState: state, 312 remote: sc.remote, 313 } 314 } 315 316 // Equal is a predicate that determines whether two SpanContext values are equal. 317 func (sc SpanContext) Equal(other SpanContext) bool { 318 return sc.traceID == other.traceID && 319 sc.spanID == other.spanID && 320 sc.traceFlags == other.traceFlags && 321 sc.traceState.String() == other.traceState.String() && 322 sc.remote == other.remote 323 } 324 325 // MarshalJSON implements a custom marshal function to encode a SpanContext. 326 func (sc SpanContext) MarshalJSON() ([]byte, error) { 327 return json.Marshal(SpanContextConfig{ 328 TraceID: sc.traceID, 329 SpanID: sc.spanID, 330 TraceFlags: sc.traceFlags, 331 TraceState: sc.traceState, 332 Remote: sc.remote, 333 }) 334 } 335 336 // Span is the individual component of a trace. It represents a single named 337 // and timed operation of a workflow that is traced. A Tracer is used to 338 // create a Span and it is then up to the operation the Span represents to 339 // properly end the Span when the operation itself ends. 340 // 341 // Warning: methods may be added to this interface in minor releases. 342 type Span interface { 343 // End completes the Span. The Span is considered complete and ready to be 344 // delivered through the rest of the telemetry pipeline after this method 345 // is called. Therefore, updates to the Span are not allowed after this 346 // method has been called. 347 End(options ...SpanEndOption) 348 349 // AddEvent adds an event with the provided name and options. 350 AddEvent(name string, options ...EventOption) 351 352 // IsRecording returns the recording state of the Span. It will return 353 // true if the Span is active and events can be recorded. 354 IsRecording() bool 355 356 // RecordError will record err as an exception span event for this span. An 357 // additional call to SetStatus is required if the Status of the Span should 358 // be set to Error, as this method does not change the Span status. If this 359 // span is not being recorded or err is nil then this method does nothing. 360 RecordError(err error, options ...EventOption) 361 362 // SpanContext returns the SpanContext of the Span. The returned SpanContext 363 // is usable even after the End method has been called for the Span. 364 SpanContext() SpanContext 365 366 // SetStatus sets the status of the Span in the form of a code and a 367 // description, provided the status hasn't already been set to a higher 368 // value before (OK > Error > Unset). The description is only included in a 369 // status when the code is for an error. 370 SetStatus(code codes.Code, description string) 371 372 // SetName sets the Span name. 373 SetName(name string) 374 375 // SetAttributes sets kv as attributes of the Span. If a key from kv 376 // already exists for an attribute of the Span it will be overwritten with 377 // the value contained in kv. 378 SetAttributes(kv ...attribute.KeyValue) 379 380 // TracerProvider returns a TracerProvider that can be used to generate 381 // additional Spans on the same telemetry pipeline as the current Span. 382 TracerProvider() TracerProvider 383 } 384 385 // Link is the relationship between two Spans. The relationship can be within 386 // the same Trace or across different Traces. 387 // 388 // For example, a Link is used in the following situations: 389 // 390 // 1. Batch Processing: A batch of operations may contain operations 391 // associated with one or more traces/spans. Since there can only be one 392 // parent SpanContext, a Link is used to keep reference to the 393 // SpanContext of all operations in the batch. 394 // 2. Public Endpoint: A SpanContext for an in incoming client request on a 395 // public endpoint should be considered untrusted. In such a case, a new 396 // trace with its own identity and sampling decision needs to be created, 397 // but this new trace needs to be related to the original trace in some 398 // form. A Link is used to keep reference to the original SpanContext and 399 // track the relationship. 400 type Link struct { 401 // SpanContext of the linked Span. 402 SpanContext SpanContext 403 404 // Attributes describe the aspects of the link. 405 Attributes []attribute.KeyValue 406 } 407 408 // LinkFromContext returns a link encapsulating the SpanContext in the provided ctx. 409 func LinkFromContext(ctx context.Context, attrs ...attribute.KeyValue) Link { 410 return Link{ 411 SpanContext: SpanContextFromContext(ctx), 412 Attributes: attrs, 413 } 414 } 415 416 // SpanKind is the role a Span plays in a Trace. 417 type SpanKind int 418 419 // As a convenience, these match the proto definition, see 420 // https://github.com/open-telemetry/opentelemetry-proto/blob/30d237e1ff3ab7aa50e0922b5bebdd93505090af/opentelemetry/proto/trace/v1/trace.proto#L101-L129 421 // 422 // The unspecified value is not a valid `SpanKind`. Use `ValidateSpanKind()` 423 // to coerce a span kind to a valid value. 424 const ( 425 // SpanKindUnspecified is an unspecified SpanKind and is not a valid 426 // SpanKind. SpanKindUnspecified should be replaced with SpanKindInternal 427 // if it is received. 428 SpanKindUnspecified SpanKind = 0 429 // SpanKindInternal is a SpanKind for a Span that represents an internal 430 // operation within an application. 431 SpanKindInternal SpanKind = 1 432 // SpanKindServer is a SpanKind for a Span that represents the operation 433 // of handling a request from a client. 434 SpanKindServer SpanKind = 2 435 // SpanKindClient is a SpanKind for a Span that represents the operation 436 // of client making a request to a server. 437 SpanKindClient SpanKind = 3 438 // SpanKindProducer is a SpanKind for a Span that represents the operation 439 // of a producer sending a message to a message broker. Unlike 440 // SpanKindClient and SpanKindServer, there is often no direct 441 // relationship between this kind of Span and a SpanKindConsumer kind. A 442 // SpanKindProducer Span will end once the message is accepted by the 443 // message broker which might not overlap with the processing of that 444 // message. 445 SpanKindProducer SpanKind = 4 446 // SpanKindConsumer is a SpanKind for a Span that represents the operation 447 // of a consumer receiving a message from a message broker. Like 448 // SpanKindProducer Spans, there is often no direct relationship between 449 // this Span and the Span that produced the message. 450 SpanKindConsumer SpanKind = 5 451 ) 452 453 // ValidateSpanKind returns a valid span kind value. This will coerce 454 // invalid values into the default value, SpanKindInternal. 455 func ValidateSpanKind(spanKind SpanKind) SpanKind { 456 switch spanKind { 457 case SpanKindInternal, 458 SpanKindServer, 459 SpanKindClient, 460 SpanKindProducer, 461 SpanKindConsumer: 462 // valid 463 return spanKind 464 default: 465 return SpanKindInternal 466 } 467 } 468 469 // String returns the specified name of the SpanKind in lower-case. 470 func (sk SpanKind) String() string { 471 switch sk { 472 case SpanKindInternal: 473 return "internal" 474 case SpanKindServer: 475 return "server" 476 case SpanKindClient: 477 return "client" 478 case SpanKindProducer: 479 return "producer" 480 case SpanKindConsumer: 481 return "consumer" 482 default: 483 return "unspecified" 484 } 485 } 486 487 // Tracer is the creator of Spans. 488 // 489 // Warning: methods may be added to this interface in minor releases. 490 type Tracer interface { 491 // Start creates a span and a context.Context containing the newly-created span. 492 // 493 // If the context.Context provided in `ctx` contains a Span then the newly-created 494 // Span will be a child of that span, otherwise it will be a root span. This behavior 495 // can be overridden by providing `WithNewRoot()` as a SpanOption, causing the 496 // newly-created Span to be a root span even if `ctx` contains a Span. 497 // 498 // When creating a Span it is recommended to provide all known span attributes using 499 // the `WithAttributes()` SpanOption as samplers will only have access to the 500 // attributes provided when a Span is created. 501 // 502 // Any Span that is created MUST also be ended. This is the responsibility of the user. 503 // Implementations of this API may leak memory or other resources if Spans are not ended. 504 Start(ctx context.Context, spanName string, opts ...SpanStartOption) (context.Context, Span) 505 } 506 507 // TracerProvider provides Tracers that are used by instrumentation code to 508 // trace computational workflows. 509 // 510 // A TracerProvider is the collection destination of all Spans from Tracers it 511 // provides, it represents a unique telemetry collection pipeline. How that 512 // pipeline is defined, meaning how those Spans are collected, processed, and 513 // where they are exported, depends on its implementation. Instrumentation 514 // authors do not need to define this implementation, rather just use the 515 // provided Tracers to instrument code. 516 // 517 // Commonly, instrumentation code will accept a TracerProvider implementation 518 // at runtime from its users or it can simply use the globally registered one 519 // (see https://pkg.go.dev/go.opentelemetry.io/otel#GetTracerProvider). 520 // 521 // Warning: methods may be added to this interface in minor releases. 522 type TracerProvider interface { 523 // Tracer returns a unique Tracer scoped to be used by instrumentation code 524 // to trace computational workflows. The scope and identity of that 525 // instrumentation code is uniquely defined by the name and options passed. 526 // 527 // The passed name needs to uniquely identify instrumentation code. 528 // Therefore, it is recommended that name is the Go package name of the 529 // library providing instrumentation (note: not the code being 530 // instrumented). Instrumentation libraries can have multiple versions, 531 // therefore, the WithInstrumentationVersion option should be used to 532 // distinguish these different codebases. Additionally, instrumentation 533 // libraries may sometimes use traces to communicate different domains of 534 // workflow data (i.e. using spans to communicate workflow events only). If 535 // this is the case, the WithScopeAttributes option should be used to 536 // uniquely identify Tracers that handle the different domains of workflow 537 // data. 538 // 539 // If the same name and options are passed multiple times, the same Tracer 540 // will be returned (it is up to the implementation if this will be the 541 // same underlying instance of that Tracer or not). It is not necessary to 542 // call this multiple times with the same name and options to get an 543 // up-to-date Tracer. All implementations will ensure any TracerProvider 544 // configuration changes are propagated to all provided Tracers. 545 // 546 // If name is empty, then an implementation defined default name will be 547 // used instead. 548 // 549 // This method is safe to call concurrently. 550 Tracer(name string, options ...TracerOption) Tracer 551 }