| // Copyright 2017 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // Package tracecontext provides encoders and decoders for Stackdriver Trace contexts. |
| package tracecontext |
| |
| import "encoding/binary" |
| |
| const ( |
| versionID = 0 |
| traceIDField = 0 |
| spanIDField = 1 |
| optsField = 2 |
| |
| traceIDLen = 16 |
| spanIDLen = 8 |
| optsLen = 1 |
| |
| // Len represents the length of trace context. |
| Len = 1 + 1 + traceIDLen + 1 + spanIDLen + 1 + optsLen |
| ) |
| |
| // Encode encodes trace ID, span ID and options into dst. The number of bytes |
| // written will be returned. If len(dst) isn't big enough to fit the trace context, |
| // a negative number is returned. |
| func Encode(dst []byte, traceID []byte, spanID uint64, opts byte) (n int) { |
| if len(dst) < Len { |
| return -1 |
| } |
| var offset = 0 |
| putByte := func(b byte) { dst[offset] = b; offset++ } |
| putUint64 := func(u uint64) { binary.LittleEndian.PutUint64(dst[offset:], u); offset += 8 } |
| |
| putByte(versionID) |
| putByte(traceIDField) |
| for _, b := range traceID { |
| putByte(b) |
| } |
| putByte(spanIDField) |
| putUint64(spanID) |
| putByte(optsField) |
| putByte(opts) |
| |
| return offset |
| } |
| |
| // Decode decodes the src into a trace ID, span ID and options. If src doesn't |
| // contain a valid trace context, ok = false is returned. |
| func Decode(src []byte) (traceID []byte, spanID uint64, opts byte, ok bool) { |
| if len(src) < Len { |
| return traceID, spanID, 0, false |
| } |
| var offset = 0 |
| readByte := func() byte { b := src[offset]; offset++; return b } |
| readUint64 := func() uint64 { v := binary.LittleEndian.Uint64(src[offset:]); offset += 8; return v } |
| |
| if readByte() != versionID { |
| return traceID, spanID, 0, false |
| } |
| for offset < len(src) { |
| switch readByte() { |
| case traceIDField: |
| traceID = src[offset : offset+traceIDLen] |
| offset += traceIDLen |
| case spanIDField: |
| spanID = readUint64() |
| case optsField: |
| opts = readByte() |
| } |
| } |
| return traceID, spanID, opts, true |
| } |