gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }