You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
4.5 KiB
178 lines
4.5 KiB
6 years ago
|
package trace
|
||
|
|
||
|
import (
|
||
|
errs "errors"
|
||
|
"net/http"
|
||
|
|
||
|
"google.golang.org/grpc/metadata"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
// ErrUnsupportedFormat occurs when the `format` passed to Tracer.Inject() or
|
||
|
// Tracer.Extract() is not recognized by the Tracer implementation.
|
||
|
ErrUnsupportedFormat = errs.New("trace: Unknown or unsupported Inject/Extract format")
|
||
|
|
||
|
// ErrTraceNotFound occurs when the `carrier` passed to
|
||
|
// Tracer.Extract() is valid and uncorrupted but has insufficient
|
||
|
// information to extract a Trace.
|
||
|
ErrTraceNotFound = errs.New("trace: Trace not found in Extract carrier")
|
||
|
|
||
|
// ErrInvalidTrace errors occur when Tracer.Inject() is asked to
|
||
|
// operate on a Trace which it is not prepared to handle (for
|
||
|
// example, since it was created by a different tracer implementation).
|
||
|
ErrInvalidTrace = errs.New("trace: Trace type incompatible with tracer")
|
||
|
|
||
|
// ErrInvalidCarrier errors occur when Tracer.Inject() or Tracer.Extract()
|
||
|
// implementations expect a different type of `carrier` than they are
|
||
|
// given.
|
||
|
ErrInvalidCarrier = errs.New("trace: Invalid Inject/Extract carrier")
|
||
|
|
||
|
// ErrTraceCorrupted occurs when the `carrier` passed to
|
||
|
// Tracer.Extract() is of the expected type but is corrupted.
|
||
|
ErrTraceCorrupted = errs.New("trace: Trace data corrupted in Extract carrier")
|
||
|
)
|
||
|
|
||
|
// BuiltinFormat is used to demarcate the values within package `trace`
|
||
|
// that are intended for use with the Tracer.Inject() and Tracer.Extract()
|
||
|
// methods.
|
||
|
type BuiltinFormat byte
|
||
|
|
||
|
// support format list
|
||
|
const (
|
||
|
// HTTPFormat represents Trace as HTTP header string pairs.
|
||
|
//
|
||
|
// the HTTPFormat format requires that the keys and values
|
||
|
// be valid as HTTP headers as-is (i.e., character casing may be unstable
|
||
|
// and special characters are disallowed in keys, values should be
|
||
|
// URL-escaped, etc).
|
||
|
//
|
||
|
// the carrier must be a `http.Header`.
|
||
|
HTTPFormat BuiltinFormat = iota
|
||
|
// GRPCFormat represents Trace as gRPC metadata.
|
||
|
//
|
||
|
// the carrier must be a `google.golang.org/grpc/metadata.MD`.
|
||
|
GRPCFormat
|
||
|
)
|
||
|
|
||
|
// Carrier propagator must convert generic interface{} to something this
|
||
|
// implement Carrier interface, Trace can use Carrier to represents itself.
|
||
|
type Carrier interface {
|
||
|
Set(key, val string)
|
||
|
Get(key string) string
|
||
|
}
|
||
|
|
||
|
// propagator is responsible for injecting and extracting `Trace` instances
|
||
|
// from a format-specific "carrier"
|
||
|
type propagator interface {
|
||
|
Inject(carrier interface{}) (Carrier, error)
|
||
|
Extract(carrier interface{}) (Carrier, error)
|
||
|
}
|
||
|
|
||
|
type httpPropagator struct{}
|
||
|
|
||
|
type httpCarrier http.Header
|
||
|
|
||
|
func (h httpCarrier) Set(key, val string) {
|
||
|
http.Header(h).Set(key, val)
|
||
|
}
|
||
|
|
||
|
func (h httpCarrier) Get(key string) string {
|
||
|
return http.Header(h).Get(key)
|
||
|
}
|
||
|
|
||
|
func (httpPropagator) Inject(carrier interface{}) (Carrier, error) {
|
||
|
header, ok := carrier.(http.Header)
|
||
|
if !ok {
|
||
|
return nil, ErrInvalidCarrier
|
||
|
}
|
||
|
if header == nil {
|
||
|
return nil, ErrInvalidTrace
|
||
|
}
|
||
|
return httpCarrier(header), nil
|
||
|
}
|
||
|
|
||
|
func (httpPropagator) Extract(carrier interface{}) (Carrier, error) {
|
||
|
header, ok := carrier.(http.Header)
|
||
|
if !ok {
|
||
|
return nil, ErrInvalidCarrier
|
||
|
}
|
||
|
if header == nil {
|
||
|
return nil, ErrTraceNotFound
|
||
|
}
|
||
|
return httpCarrier(header), nil
|
||
|
}
|
||
|
|
||
|
const legacyGRPCKey = "trace"
|
||
|
|
||
|
type grpcPropagator struct{}
|
||
|
|
||
|
type grpcCarrier map[string][]string
|
||
|
|
||
|
func (g grpcCarrier) Get(key string) string {
|
||
|
if v, ok := g[key]; ok && len(v) > 0 {
|
||
|
return v[0]
|
||
|
}
|
||
|
// ts := g[legacyGRPCKey]
|
||
|
// if len(ts) != 8 {
|
||
|
// return ""
|
||
|
// }
|
||
|
// switch key {
|
||
|
// case KeyTraceID:
|
||
|
// return ts[0]
|
||
|
// case KeyTraceSpanID:
|
||
|
// return ts[1]
|
||
|
// case KeyTraceParentID:
|
||
|
// return ts[2]
|
||
|
// case KeyTraceLevel:
|
||
|
// return ts[3]
|
||
|
// case KeyTraceSampled:
|
||
|
// return ts[4]
|
||
|
// case KeyTraceCaller:
|
||
|
// return ts[5]
|
||
|
// }
|
||
|
return ""
|
||
|
}
|
||
|
|
||
|
func (g grpcCarrier) Set(key, val string) {
|
||
|
// ts := make([]string, 8)
|
||
|
// g[legacyGRPCKey] = ts
|
||
|
// switch key {
|
||
|
// case KeyTraceID:
|
||
|
// ts[0] = val
|
||
|
// case KeyTraceSpanID:
|
||
|
// ts[1] = val
|
||
|
// case KeyTraceParentID:
|
||
|
// ts[2] = val
|
||
|
// case KeyTraceLevel:
|
||
|
// ts[3] = val
|
||
|
// case KeyTraceSampled:
|
||
|
// ts[4] = val
|
||
|
// case KeyTraceCaller:
|
||
|
// ts[5] = val
|
||
|
// default:
|
||
|
g[key] = append(g[key], val)
|
||
|
// }
|
||
|
}
|
||
|
|
||
|
func (grpcPropagator) Inject(carrier interface{}) (Carrier, error) {
|
||
|
md, ok := carrier.(metadata.MD)
|
||
|
if !ok {
|
||
|
return nil, ErrInvalidCarrier
|
||
|
}
|
||
|
if md == nil {
|
||
|
return nil, ErrInvalidTrace
|
||
|
}
|
||
|
return grpcCarrier(md), nil
|
||
|
}
|
||
|
|
||
|
func (grpcPropagator) Extract(carrier interface{}) (Carrier, error) {
|
||
|
md, ok := carrier.(metadata.MD)
|
||
|
if !ok {
|
||
|
return nil, ErrInvalidCarrier
|
||
|
}
|
||
|
if md == nil {
|
||
|
return nil, ErrTraceNotFound
|
||
|
}
|
||
|
return grpcCarrier(md), nil
|
||
|
}
|