github.com/kiali/kiali@v1.84.0/tracing/jaeger/model/ids.go (about) 1 // Copyright (c) 2019 The Jaeger Authors. 2 // Copyright (c) 2018 Uber Technologies, Inc. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 // Cloned from github.com/jaegertracing/jaeger/ 17 18 // nolint 19 package model 20 21 import ( 22 "encoding/base64" 23 "encoding/binary" 24 "fmt" 25 "strconv" 26 ) 27 28 const ( 29 // traceIDShortBytesLen indicates length of 64bit traceID when represented as list of bytes 30 traceIDShortBytesLen = 8 31 // traceIDLongBytesLen indicates length of 128bit traceID when represented as list of bytes 32 traceIDLongBytesLen = 16 33 ) 34 35 // TraceID is a random 128bit identifier for a trace 36 type TraceID struct { 37 Low uint64 `json:"lo"` 38 High uint64 `json:"hi"` 39 } 40 41 // SpanID is a random 64bit identifier for a span 42 type SpanID uint64 43 44 // ------- TraceID ------- 45 46 // NewTraceID creates a new TraceID from two 64bit unsigned ints. 47 func NewTraceID(high, low uint64) TraceID { 48 return TraceID{High: high, Low: low} 49 } 50 51 func (t TraceID) String() string { 52 if t.High == 0 { 53 return fmt.Sprintf("%016x", t.Low) 54 } 55 return fmt.Sprintf("%016x%016x", t.High, t.Low) 56 } 57 58 // TraceIDFromString creates a TraceID from a hexadecimal string 59 func TraceIDFromString(s string) (TraceID, error) { 60 var hi, lo uint64 61 var err error 62 switch { 63 case len(s) > 32: 64 return TraceID{}, fmt.Errorf("TraceID cannot be longer than 32 hex characters: %s", s) 65 case len(s) > 16: 66 hiLen := len(s) - 16 67 if hi, err = strconv.ParseUint(s[0:hiLen], 16, 64); err != nil { 68 return TraceID{}, err 69 } 70 if lo, err = strconv.ParseUint(s[hiLen:], 16, 64); err != nil { 71 return TraceID{}, err 72 } 73 default: 74 if lo, err = strconv.ParseUint(s, 16, 64); err != nil { 75 return TraceID{}, err 76 } 77 } 78 return TraceID{High: hi, Low: lo}, nil 79 } 80 81 // TraceIDFromBytes creates a TraceID from list of bytes 82 func TraceIDFromBytes(data []byte) (TraceID, error) { 83 var t TraceID 84 switch { 85 case len(data) == traceIDLongBytesLen: 86 t.High = binary.BigEndian.Uint64(data[:traceIDShortBytesLen]) 87 t.Low = binary.BigEndian.Uint64(data[traceIDShortBytesLen:]) 88 case len(data) == traceIDShortBytesLen: 89 t.Low = binary.BigEndian.Uint64(data) 90 default: 91 return TraceID{}, fmt.Errorf("invalid length for TraceID") 92 } 93 return t, nil 94 } 95 96 // MarshalText is called by encoding/json, which we do not want people to use. 97 func (t TraceID) MarshalText() ([]byte, error) { 98 return nil, fmt.Errorf("unsupported method TraceID.MarshalText; please use github.com/gogo/protobuf/jsonpb for marshalling") 99 } 100 101 // UnmarshalText is called by encoding/json, which we do not want people to use. 102 func (t *TraceID) UnmarshalText(text []byte) error { 103 return fmt.Errorf("unsupported method TraceID.UnmarshalText; please use github.com/gogo/protobuf/jsonpb for marshalling") 104 } 105 106 // Size returns the size of this datum in protobuf. It is always 16 bytes. 107 func (t *TraceID) Size() int { 108 return 16 109 } 110 111 // MarshalTo converts trace ID into a binary representation. Called by protobuf serialization. 112 func (t *TraceID) MarshalTo(data []byte) (n int, err error) { 113 var b [16]byte 114 binary.BigEndian.PutUint64(b[:8], uint64(t.High)) 115 binary.BigEndian.PutUint64(b[8:], uint64(t.Low)) 116 return marshalBytes(data, b[:]) 117 } 118 119 // Unmarshal inflates this trace ID from binary representation. Called by protobuf serialization. 120 func (t *TraceID) Unmarshal(data []byte) error { 121 var err error 122 *t, err = TraceIDFromBytes(data) 123 return err 124 } 125 126 func marshalBytes(dst []byte, src []byte) (n int, err error) { 127 if len(dst) < len(src) { 128 return 0, fmt.Errorf("buffer is too short") 129 } 130 return copy(dst, src), nil 131 } 132 133 // MarshalJSON converts trace id into a base64 string enclosed in quotes. 134 // Used by protobuf JSON serialization. 135 // Example: {high:2, low:1} => "AAAAAAAAAAIAAAAAAAAAAQ==". 136 func (t TraceID) MarshalJSON() ([]byte, error) { 137 var b [16]byte 138 t.MarshalTo(b[:]) // can only error on incorrect buffer size 139 s := make([]byte, 24+2) 140 base64.StdEncoding.Encode(s[1:25], b[:]) 141 s[0], s[25] = '"', '"' 142 return s, nil 143 } 144 145 // UnmarshalJSON inflates trace id from base64 string, possibly enclosed in quotes. 146 // User by protobuf JSON serialization. 147 func (t *TraceID) UnmarshalJSON(data []byte) error { 148 s := string(data) 149 if l := len(s); l > 2 && s[0] == '"' && s[l-1] == '"' { 150 s = s[1 : l-1] 151 } 152 b, err := base64.StdEncoding.DecodeString(s) 153 if err != nil { 154 return fmt.Errorf("cannot unmarshal TraceID from string '%s': %v", string(data), err) 155 } 156 return t.Unmarshal(b) 157 } 158 159 // ------- SpanID ------- 160 161 // NewSpanID creates a new SpanID from a 64bit unsigned int. 162 func NewSpanID(v uint64) SpanID { 163 return SpanID(v) 164 } 165 166 func (s SpanID) String() string { 167 return fmt.Sprintf("%016x", uint64(s)) 168 } 169 170 // SpanIDFromString creates a SpanID from a hexadecimal string 171 func SpanIDFromString(s string) (SpanID, error) { 172 if len(s) > 16 { 173 return SpanID(0), fmt.Errorf("SpanID cannot be longer than 16 hex characters: %s", s) 174 } 175 id, err := strconv.ParseUint(s, 16, 64) 176 if err != nil { 177 return SpanID(0), err 178 } 179 return SpanID(id), nil 180 } 181 182 // SpanIDFromBytes creates a SpandID from list of bytes 183 func SpanIDFromBytes(data []byte) (SpanID, error) { 184 if len(data) != traceIDShortBytesLen { 185 return SpanID(0), fmt.Errorf("invalid length for SpanID") 186 } 187 return NewSpanID(binary.BigEndian.Uint64(data)), nil 188 } 189 190 // MarshalText is called by encoding/json, which we do not want people to use. 191 func (s SpanID) MarshalText() ([]byte, error) { 192 return nil, fmt.Errorf("unsupported method SpanID.MarshalText; please use github.com/gogo/protobuf/jsonpb for marshalling") 193 } 194 195 // UnmarshalText is called by encoding/json, which we do not want people to use. 196 func (s *SpanID) UnmarshalText(text []byte) error { 197 return fmt.Errorf("unsupported method SpanID.UnmarshalText; please use github.com/gogo/protobuf/jsonpb for marshalling") 198 } 199 200 // Size returns the size of this datum in protobuf. It is always 8 bytes. 201 func (s *SpanID) Size() int { 202 return 8 203 } 204 205 // MarshalTo converts span ID into a binary representation. Called by protobuf serialization. 206 func (s *SpanID) MarshalTo(data []byte) (n int, err error) { 207 var b [8]byte 208 binary.BigEndian.PutUint64(b[:], uint64(*s)) 209 return marshalBytes(data, b[:]) 210 } 211 212 // Unmarshal inflates span ID from a binary representation. Called by protobuf serialization. 213 func (s *SpanID) Unmarshal(data []byte) error { 214 var err error 215 *s, err = SpanIDFromBytes(data) 216 return err 217 } 218 219 // MarshalJSON converts span id into a base64 string enclosed in quotes. 220 // Used by protobuf JSON serialization. 221 // Example: {1} => "AAAAAAAAAAE=". 222 func (s SpanID) MarshalJSON() ([]byte, error) { 223 var b [8]byte 224 s.MarshalTo(b[:]) // can only error on incorrect buffer size 225 v := make([]byte, 12+2) 226 base64.StdEncoding.Encode(v[1:13], b[:]) 227 v[0], v[13] = '"', '"' 228 return v, nil 229 } 230 231 // UnmarshalJSON inflates span id from base64 string, possibly enclosed in quotes. 232 // User by protobuf JSON serialization. 233 // 234 // There appears to be a bug in gogoproto, as this function is only called for numeric values. 235 // https://github.com/gogo/protobuf/issues/411#issuecomment-393856837 236 func (s *SpanID) UnmarshalJSON(data []byte) error { 237 str := string(data) 238 if l := len(str); l > 2 && str[0] == '"' && str[l-1] == '"' { 239 str = str[1 : l-1] 240 } 241 b, err := base64.StdEncoding.DecodeString(str) 242 if err != nil { 243 return fmt.Errorf("cannot unmarshal SpanID from string '%s': %v", string(data), err) 244 } 245 return s.Unmarshal(b) 246 }