blob: 914ce5f5ac32bf02d824dfb49a7fa81dd776a62e [file] [log] [blame]
Joey Armstrong903c69d2024-02-01 19:46:39 -05001// 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
15package trace
16
17import (
18 "bytes"
19 "encoding/hex"
20 "encoding/json"
21)
22
23const (
24 // FlagsSampled is a bitmask with the sampled bit set. A SpanContext
25 // with the sampling bit set means the span is sampled.
26 FlagsSampled = byte(0x01)
27 // FlagsDeferred is a bitmask with the deferred bit set. A SpanContext
28 // with the deferred bit set means the sampling decision has been
29 // defered to the receiver.
30 FlagsDeferred = byte(0x02)
31 // FlagsDebug is a bitmask with the debug bit set.
32 FlagsDebug = byte(0x04)
33
34 ErrInvalidHexID errorConst = "trace-id and span-id can only contain [0-9a-f] characters, all lowercase"
35
36 ErrInvalidTraceIDLength errorConst = "hex encoded trace-id must have length equals to 32"
37 ErrNilTraceID errorConst = "trace-id can't be all zero"
38
39 ErrInvalidSpanIDLength errorConst = "hex encoded span-id must have length equals to 16"
40 ErrNilSpanID errorConst = "span-id can't be all zero"
41)
42
43type errorConst string
44
45func (e errorConst) Error() string {
46 return string(e)
47}
48
49// ID is a unique identity of a trace.
50type ID [16]byte
51
52var nilTraceID ID
53var _ json.Marshaler = nilTraceID
54
55// IsValid checks whether the trace ID is valid. A valid trace ID does
56// not consist of zeros only.
57func (t ID) IsValid() bool {
58 return !bytes.Equal(t[:], nilTraceID[:])
59}
60
61// MarshalJSON implements a custom marshal function to encode TraceID
62// as a hex string.
63func (t ID) MarshalJSON() ([]byte, error) {
64 return json.Marshal(t.String())
65}
66
67// String returns the hex string representation form of a TraceID
68func (t ID) String() string {
69 return hex.EncodeToString(t[:])
70}
71
72// SpanID is a unique identify of a span in a trace.
73type SpanID [8]byte
74
75var nilSpanID SpanID
76var _ json.Marshaler = nilSpanID
77
78// IsValid checks whether the span ID is valid. A valid span ID does
79// not consist of zeros only.
80func (s SpanID) IsValid() bool {
81 return !bytes.Equal(s[:], nilSpanID[:])
82}
83
84// MarshalJSON implements a custom marshal function to encode SpanID
85// as a hex string.
86func (s SpanID) MarshalJSON() ([]byte, error) {
87 return json.Marshal(s.String())
88}
89
90// String returns the hex string representation form of a SpanID
91func (s SpanID) String() string {
92 return hex.EncodeToString(s[:])
93}
94
95// IDFromHex returns a TraceID from a hex string if it is compliant
96// with the w3c trace-context specification.
97// See more at https://www.w3.org/TR/trace-context/#trace-id
98func IDFromHex(h string) (ID, error) {
99 t := ID{}
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
117func 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
133func 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// SpanContext contains basic information about the span - its trace
155// ID, span ID and trace flags.
156type SpanContext struct {
157 TraceID ID
158 SpanID SpanID
159 TraceFlags byte
160}
161
162// EmptySpanContext is meant for internal use to return invalid span
163// context during error conditions.
164func EmptySpanContext() SpanContext {
165 return SpanContext{}
166}
167
168// IsValid checks if the span context is valid. A valid span context
169// has a valid trace ID and a valid span ID.
170func (sc SpanContext) IsValid() bool {
171 return sc.HasTraceID() && sc.HasSpanID()
172}
173
174// HasTraceID checks if the span context has a valid trace ID.
175func (sc SpanContext) HasTraceID() bool {
176 return sc.TraceID.IsValid()
177}
178
179// HasSpanID checks if the span context has a valid span ID.
180func (sc SpanContext) HasSpanID() bool {
181 return sc.SpanID.IsValid()
182}
183
184// IsDeferred returns if the deferred bit is set in the trace flags.
185func (sc SpanContext) IsDeferred() bool {
186 return sc.TraceFlags&FlagsDeferred == FlagsDeferred
187}
188
189// IsDebug returns if the debug bit is set in the trace flags.
190func (sc SpanContext) IsDebug() bool {
191 return sc.TraceFlags&FlagsDebug == FlagsDebug
192}
193
194// IsSampled returns if the sampling bit is set in the trace flags.
195func (sc SpanContext) IsSampled() bool {
196 return sc.TraceFlags&FlagsSampled == FlagsSampled
197}