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  }