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