trace.go 19 KB

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