1// Copyright 2017 Google LLC 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 15// Package tracecontext provides encoders and decoders for Stackdriver Trace contexts. 16package tracecontext 17 18import "encoding/binary" 19 20const ( 21 versionID = 0 22 traceIDField = 0 23 spanIDField = 1 24 optsField = 2 25 26 traceIDLen = 16 27 spanIDLen = 8 28 optsLen = 1 29 30 // Len represents the length of trace context. 31 Len = 1 + 1 + traceIDLen + 1 + spanIDLen + 1 + optsLen 32) 33 34// Encode encodes trace ID, span ID and options into dst. The number of bytes 35// written will be returned. If len(dst) isn't big enough to fit the trace context, 36// a negative number is returned. 37func Encode(dst []byte, traceID []byte, spanID uint64, opts byte) (n int) { 38 if len(dst) < Len { 39 return -1 40 } 41 var offset = 0 42 putByte := func(b byte) { dst[offset] = b; offset++ } 43 putUint64 := func(u uint64) { binary.LittleEndian.PutUint64(dst[offset:], u); offset += 8 } 44 45 putByte(versionID) 46 putByte(traceIDField) 47 for _, b := range traceID { 48 putByte(b) 49 } 50 putByte(spanIDField) 51 putUint64(spanID) 52 putByte(optsField) 53 putByte(opts) 54 55 return offset 56} 57 58// Decode decodes the src into a trace ID, span ID and options. If src doesn't 59// contain a valid trace context, ok = false is returned. 60func Decode(src []byte) (traceID []byte, spanID uint64, opts byte, ok bool) { 61 if len(src) < Len { 62 return traceID, spanID, 0, false 63 } 64 var offset = 0 65 readByte := func() byte { b := src[offset]; offset++; return b } 66 readUint64 := func() uint64 { v := binary.LittleEndian.Uint64(src[offset:]); offset += 8; return v } 67 68 if readByte() != versionID { 69 return traceID, spanID, 0, false 70 } 71 for offset < len(src) { 72 switch readByte() { 73 case traceIDField: 74 traceID = src[offset : offset+traceIDLen] 75 offset += traceIDLen 76 case spanIDField: 77 spanID = readUint64() 78 case optsField: 79 opts = readByte() 80 } 81 } 82 return traceID, spanID, opts, true 83} 84