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 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} 198