mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2024-12-24 20:14:40 +02:00
Add propagator interface and W3C propagator (#85)
* add propagation api. * add http propagator interface and w3c propagator implementation. * remove Extract api from trace. * remove Extract interface for tracer. * fix copyright. * fix variable names and comments. * move inject/extract out of trace. * replace INVALID_SPAN_CONTEXT with EmptySpanContext function. * fix tag.Map. * make carrier as interface instead of http.Request. * rename structs and update doc comments.. * add doc.go * update doc. * add noop propagator. * add new propagation api with Supplier interface. - added Default Tracer which simply propagates SpanContext. - added CopyOfRemote option to simply create remote span. * remove old propagator. * rename propagator to TextFormatPropagator. * rename default tracer/span as pass_through tracer/span. * add test for pass through tracer. * add missing interface to pass through tracer. * return SpanContext instead of contex.Context from Extract interface. - also remove PassThroughTracer * fix review comments. * add more test cases for traceContext extraction. * remove tidy temporarily from circle-ci target to avoid build failure. * allow header ending in dash '-'. * add inject test for non-zero value other than 01 for traceoption * add AddLink and Link interface to MockSpan * fix running go mod tidy on every build.
This commit is contained in:
parent
b13362e37c
commit
83935b2558
16
api/propagation/doc.go
Normal file
16
api/propagation/doc.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2019, OpenTelemetry Authors
|
||||||
|
//
|
||||||
|
// 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 propagation contains interface definition for Binary and TextFormat propagators.
|
||||||
|
package propagation // import "go.opentelemetry.io/api/propagation"
|
40
api/propagation/noop_propagator.go
Normal file
40
api/propagation/noop_propagator.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright 2019, OpenTelemetry Authors
|
||||||
|
//
|
||||||
|
// 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 propagation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/api/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NoopTextFormatPropagator implements TextFormatPropagator that does nothing.
|
||||||
|
type NoopTextFormatPropagator struct{}
|
||||||
|
|
||||||
|
var _ TextFormatPropagator = NoopTextFormatPropagator{}
|
||||||
|
|
||||||
|
// Inject does nothing.
|
||||||
|
func (np NoopTextFormatPropagator) Inject(ctx context.Context, supplier Supplier) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract does nothing and returns an empty SpanContext
|
||||||
|
func (np NoopTextFormatPropagator) Extract(ctx context.Context, supplier Supplier) core.SpanContext {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllKeys returns empty list of strings.
|
||||||
|
func (np NoopTextFormatPropagator) GetAllKeys() []string {
|
||||||
|
return []string{}
|
||||||
|
}
|
52
api/propagation/propagator.go
Normal file
52
api/propagation/propagator.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2019, OpenTelemetry Authors
|
||||||
|
//
|
||||||
|
// 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 propagation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/api/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TextFormatPropagator is an interface that specifies methods to inject and extract SpanContext
|
||||||
|
// into/from a carrier using Supplier interface.
|
||||||
|
// For example, HTTP Trace Context propagator would encode SpanContext into W3C Trace
|
||||||
|
// Context Header and set the header into HttpRequest.
|
||||||
|
type TextFormatPropagator interface {
|
||||||
|
// Inject method retrieves current SpanContext from the ctx, encodes it into propagator
|
||||||
|
// specific format and then injects the encoded SpanContext using supplier into a carrier
|
||||||
|
// associated with the supplier.
|
||||||
|
Inject(ctx context.Context, supplier Supplier)
|
||||||
|
|
||||||
|
// Extract method retrieves encoded SpanContext using supplier from the associated carrier.
|
||||||
|
// It decodes the SpanContext and returns it. If no SpanContext was retrieved OR
|
||||||
|
// if the retrieved SpanContext is invalid then an empty SpanContext is returned.
|
||||||
|
Extract(ctx context.Context, supplier Supplier) core.SpanContext
|
||||||
|
|
||||||
|
// GetAllKeys returns all the keys that this propagator injects/extracts into/from a
|
||||||
|
// carrier. The use cases for this are
|
||||||
|
// * allow pre-allocation of fields, especially in systems like gRPC Metadata
|
||||||
|
// * allow a single-pass over an iterator (ex OpenTracing has no getter in TextMap)
|
||||||
|
GetAllKeys() []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supplier is an interface that specifies methods to retrieve and store
|
||||||
|
// value for a key to an associated carrier.
|
||||||
|
// Get method retrieves the value for a given key.
|
||||||
|
// Set method stores the value for a given key.
|
||||||
|
type Supplier interface {
|
||||||
|
Get(key string) string
|
||||||
|
Set(key string, value string)
|
||||||
|
}
|
@ -44,9 +44,6 @@ type Tracer interface {
|
|||||||
|
|
||||||
// WithResources attaches resource attributes to the Tracer.
|
// WithResources attaches resource attributes to the Tracer.
|
||||||
WithResources(res ...core.KeyValue) Tracer
|
WithResources(res ...core.KeyValue) Tracer
|
||||||
|
|
||||||
// Note: see https://github.com/opentracing/opentracing-go/issues/127
|
|
||||||
Inject(context.Context, Span, Injector)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type FinishOptions struct {
|
type FinishOptions struct {
|
||||||
@ -102,13 +99,6 @@ type Span interface {
|
|||||||
ModifyAttributes(...tag.Mutator)
|
ModifyAttributes(...tag.Mutator)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Injector interface {
|
|
||||||
// Inject serializes span context and tag.Map and inserts them in to
|
|
||||||
// carrier associated with the injector. For example in case of http request,
|
|
||||||
// span context could added to the request (carrier) as W3C Trace context header.
|
|
||||||
Inject(core.SpanContext, tag.Map)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SpanOption apply changes to SpanOptions.
|
// SpanOption apply changes to SpanOptions.
|
||||||
type SpanOption func(*SpanOptions)
|
type SpanOption func(*SpanOptions)
|
||||||
|
|
||||||
@ -157,18 +147,6 @@ func Start(ctx context.Context, name string, opts ...SpanOption) (context.Contex
|
|||||||
return GlobalTracer().Start(ctx, name, opts...)
|
return GlobalTracer().Start(ctx, name, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject is convenient function to inject current span context using injector.
|
|
||||||
// Injector is expected to serialize span context and inject it in to a carrier.
|
|
||||||
// An example of a carrier is http request.
|
|
||||||
func Inject(ctx context.Context, injector Injector) {
|
|
||||||
span := CurrentSpan(ctx)
|
|
||||||
if span == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
span.Tracer().Inject(ctx, span, injector)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithStartTime sets the start time of the span to provided time t, when it is started.
|
// WithStartTime sets the start time of the span to provided time t, when it is started.
|
||||||
// In absensce of this option, wall clock time is used as start time.
|
// In absensce of this option, wall clock time is used as start time.
|
||||||
// This option is typically used when starting of the span is delayed.
|
// This option is typically used when starting of the span is delayed.
|
||||||
|
@ -49,7 +49,3 @@ func (NoopTracer) Start(ctx context.Context, name string, opts ...SpanOption) (c
|
|||||||
span := NoopSpan{}
|
span := NoopSpan{}
|
||||||
return SetCurrentSpan(ctx, span), span
|
return SetCurrentSpan(ctx, span), span
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject does nothing.
|
|
||||||
func (NoopTracer) Inject(ctx context.Context, span Span, injector Injector) {
|
|
||||||
}
|
|
||||||
|
@ -77,7 +77,6 @@ github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgo
|
|||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac/go.mod h1:Frd2bnT3w5FB5q49ENTfVlztJES+1k/7lyWX2+9gq/M=
|
|
||||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||||
github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
|
@ -17,6 +17,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go.opentelemetry.io/plugin/httptrace"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
@ -25,7 +26,6 @@ import (
|
|||||||
"go.opentelemetry.io/api/key"
|
"go.opentelemetry.io/api/key"
|
||||||
"go.opentelemetry.io/api/tag"
|
"go.opentelemetry.io/api/tag"
|
||||||
"go.opentelemetry.io/api/trace"
|
"go.opentelemetry.io/api/trace"
|
||||||
"go.opentelemetry.io/plugin/httptrace"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -50,9 +50,8 @@ func main() {
|
|||||||
func(ctx context.Context) error {
|
func(ctx context.Context) error {
|
||||||
req, _ := http.NewRequest("GET", "http://localhost:7777/hello", nil)
|
req, _ := http.NewRequest("GET", "http://localhost:7777/hello", nil)
|
||||||
|
|
||||||
ctx, req, inj := httptrace.W3C(ctx, req)
|
ctx, req = httptrace.W3C(ctx, req)
|
||||||
|
httptrace.Inject(ctx, req)
|
||||||
trace.Inject(ctx, inj)
|
|
||||||
|
|
||||||
res, err := client.Do(req)
|
res, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -81,8 +81,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
|||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac h1:+2b6iGRJe3hvV/yVXrd41yVEjxuFHxasJqDhkIjS4gk=
|
|
||||||
github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac/go.mod h1:Frd2bnT3w5FB5q49ENTfVlztJES+1k/7lyWX2+9gq/M=
|
|
||||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||||
github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
|
@ -35,7 +35,7 @@ var (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
helloHandler := func(w http.ResponseWriter, req *http.Request) {
|
helloHandler := func(w http.ResponseWriter, req *http.Request) {
|
||||||
attrs, tags, spanCtx := httptrace.Extract(req)
|
attrs, tags, spanCtx := httptrace.Extract(req.Context(), req)
|
||||||
|
|
||||||
req = req.WithContext(tag.WithMap(req.Context(), tag.NewMap(tag.MapUpdate{
|
req = req.WithContext(tag.WithMap(req.Context(), tag.NewMap(tag.MapUpdate{
|
||||||
MultiKV: tags,
|
MultiKV: tags,
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
|
|
||||||
"go.opentelemetry.io/api/core"
|
"go.opentelemetry.io/api/core"
|
||||||
"go.opentelemetry.io/api/key"
|
"go.opentelemetry.io/api/key"
|
||||||
"go.opentelemetry.io/api/tag"
|
|
||||||
"go.opentelemetry.io/api/trace"
|
"go.opentelemetry.io/api/trace"
|
||||||
apitrace "go.opentelemetry.io/api/trace"
|
apitrace "go.opentelemetry.io/api/trace"
|
||||||
"go.opentelemetry.io/experimental/streaming/exporter/observer"
|
"go.opentelemetry.io/experimental/streaming/exporter/observer"
|
||||||
@ -125,7 +124,3 @@ func (t *tracer) Start(ctx context.Context, name string, opts ...apitrace.SpanOp
|
|||||||
}
|
}
|
||||||
return trace.SetCurrentSpan(ctx, span), span
|
return trace.SetCurrentSpan(ctx, span), span
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tracer) Inject(ctx context.Context, span apitrace.Span, injector apitrace.Injector) {
|
|
||||||
injector.Inject(span.SpanContext(), tag.FromContext(ctx))
|
|
||||||
}
|
|
||||||
|
1
go.mod
1
go.mod
@ -8,7 +8,6 @@ require (
|
|||||||
github.com/golangci/golangci-lint v1.17.1
|
github.com/golangci/golangci-lint v1.17.1
|
||||||
github.com/google/go-cmp v0.3.0
|
github.com/google/go-cmp v0.3.0
|
||||||
github.com/hashicorp/golang-lru v0.5.3
|
github.com/hashicorp/golang-lru v0.5.3
|
||||||
github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac
|
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135
|
||||||
google.golang.org/api v0.9.0
|
google.golang.org/api v0.9.0
|
||||||
google.golang.org/grpc v1.22.1
|
google.golang.org/grpc v1.22.1
|
||||||
|
2
go.sum
2
go.sum
@ -123,8 +123,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
|||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac h1:+2b6iGRJe3hvV/yVXrd41yVEjxuFHxasJqDhkIjS4gk=
|
|
||||||
github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac/go.mod h1:Frd2bnT3w5FB5q49ENTfVlztJES+1k/7lyWX2+9gq/M=
|
|
||||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||||
github.com/magiconair/properties v1.7.6 h1:U+1DqNen04MdEPgFiIwdOUiqZ8qPa37xgogX/sd3+54=
|
github.com/magiconair/properties v1.7.6 h1:U+1DqNen04MdEPgFiIwdOUiqZ8qPa37xgogX/sd3+54=
|
||||||
github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
96
internal/trace/mock_span.go
Normal file
96
internal/trace/mock_span.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// Copyright 2019, OpenTelemetry Authors
|
||||||
|
//
|
||||||
|
// 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 trace
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/api/core"
|
||||||
|
"go.opentelemetry.io/api/tag"
|
||||||
|
apitrace "go.opentelemetry.io/api/trace"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockSpan is a mock span used in association with MockTracer for testing purpose only.
|
||||||
|
type MockSpan struct {
|
||||||
|
sc core.SpanContext
|
||||||
|
tracer apitrace.Tracer
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ apitrace.Span = (*MockSpan)(nil)
|
||||||
|
|
||||||
|
// SpanContext returns associated core.SpanContext. If the receiver is nil it returns
|
||||||
|
// an empty core.SpanContext
|
||||||
|
func (ms *MockSpan) SpanContext() core.SpanContext {
|
||||||
|
if ms == nil {
|
||||||
|
core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
return ms.sc
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsRecordingEvents always returns false for MockSpan.
|
||||||
|
func (ms *MockSpan) IsRecordingEvents() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetStatus does nothing.
|
||||||
|
func (ms *MockSpan) SetStatus(status codes.Code) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetError does nothing.
|
||||||
|
func (ms *MockSpan) SetError(v bool) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAttribute does nothing.
|
||||||
|
func (ms *MockSpan) SetAttribute(attribute core.KeyValue) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAttributes does nothing.
|
||||||
|
func (ms *MockSpan) SetAttributes(attributes ...core.KeyValue) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifyAttribute does nothing.
|
||||||
|
func (ms *MockSpan) ModifyAttribute(mutator tag.Mutator) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifyAttributes does nothing.
|
||||||
|
func (ms *MockSpan) ModifyAttributes(mutators ...tag.Mutator) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish does nothing.
|
||||||
|
func (ms *MockSpan) Finish(options ...apitrace.FinishOption) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetName does nothing.
|
||||||
|
func (ms *MockSpan) SetName(name string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracer returns MockTracer implementation of Tracer.
|
||||||
|
func (ms *MockSpan) Tracer() apitrace.Tracer {
|
||||||
|
return ms.tracer
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddEvent does nothing.
|
||||||
|
func (ms *MockSpan) AddEvent(ctx context.Context, msg string, attrs ...core.KeyValue) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddLink does nothing.
|
||||||
|
func (ms *MockSpan) AddLink(link apitrace.Link) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link does nothing.
|
||||||
|
func (ms *MockSpan) Link(sc core.SpanContext, attrs ...core.KeyValue) {
|
||||||
|
}
|
91
internal/trace/mock_tracer.go
Normal file
91
internal/trace/mock_tracer.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
// Copyright 2019, OpenTelemetry Authors
|
||||||
|
//
|
||||||
|
// 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 trace
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"math/rand"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/api/core"
|
||||||
|
apitrace "go.opentelemetry.io/api/trace"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockTracer is a simple tracer used for testing purpose only.
|
||||||
|
// It only supports ChildOf option. SpanId is atomically increased every time a
|
||||||
|
// new span is created.
|
||||||
|
type MockTracer struct {
|
||||||
|
// Sampled specifies if the new span should be sampled or not.
|
||||||
|
Sampled bool
|
||||||
|
|
||||||
|
// StartSpanId is used to initialize spanId. It is incremented by one
|
||||||
|
// every time a new span is created.
|
||||||
|
StartSpanId *uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ apitrace.Tracer = (*MockTracer)(nil)
|
||||||
|
|
||||||
|
// WithResources does nothing and returns MockTracer implementation of Tracer.
|
||||||
|
func (mt *MockTracer) WithResources(attributes ...core.KeyValue) apitrace.Tracer {
|
||||||
|
return mt
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithComponent does nothing and returns MockTracer implementation of Tracer.
|
||||||
|
func (mt *MockTracer) WithComponent(name string) apitrace.Tracer {
|
||||||
|
return mt
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithService does nothing and returns MockTracer implementation of Tracer.
|
||||||
|
func (mt *MockTracer) WithService(name string) apitrace.Tracer {
|
||||||
|
return mt
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSpan does nothing except executing the body.
|
||||||
|
func (mt *MockTracer) WithSpan(ctx context.Context, name string, body func(context.Context) error) error {
|
||||||
|
return body(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start starts a MockSpan. It creates a new Span based on Reference SpanContext option.
|
||||||
|
// TracdID is used from Reference Span Context and SpanID is assigned.
|
||||||
|
// If Reference SpanContext option is not specified then random TraceID is used.
|
||||||
|
// No other options are supported.
|
||||||
|
func (mt *MockTracer) Start(ctx context.Context, name string, o ...apitrace.SpanOption) (context.Context, apitrace.Span) {
|
||||||
|
var opts apitrace.SpanOptions
|
||||||
|
for _, op := range o {
|
||||||
|
op(&opts)
|
||||||
|
}
|
||||||
|
var span *MockSpan
|
||||||
|
var sc core.SpanContext
|
||||||
|
if !opts.Reference.SpanContext.IsValid() {
|
||||||
|
sc = core.SpanContext{
|
||||||
|
TraceID: core.TraceID{
|
||||||
|
High: rand.Uint64(),
|
||||||
|
Low: rand.Uint64(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if mt.Sampled {
|
||||||
|
sc.TraceOptions = core.TraceOptionSampled
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sc = opts.Reference.SpanContext
|
||||||
|
}
|
||||||
|
sc.SpanID = atomic.AddUint64(mt.StartSpanId, 1)
|
||||||
|
span = &MockSpan{
|
||||||
|
sc: sc,
|
||||||
|
tracer: mt,
|
||||||
|
}
|
||||||
|
|
||||||
|
return apitrace.SetCurrentSpan(ctx, span), span
|
||||||
|
}
|
@ -18,12 +18,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptrace"
|
"net/http/httptrace"
|
||||||
|
|
||||||
"go.opentelemetry.io/api/trace"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Client
|
// Client
|
||||||
func W3C(ctx context.Context, req *http.Request) (context.Context, *http.Request, trace.Injector) {
|
func W3C(ctx context.Context, req *http.Request) (context.Context, *http.Request) {
|
||||||
t := newClientTracer(ctx)
|
t := newClientTracer(ctx)
|
||||||
|
|
||||||
t.GetConn = t.getConn
|
t.GetConn = t.getConn
|
||||||
@ -45,5 +43,5 @@ func W3C(ctx context.Context, req *http.Request) (context.Context, *http.Request
|
|||||||
|
|
||||||
ctx = httptrace.WithClientTrace(ctx, &t.ClientTrace)
|
ctx = httptrace.WithClientTrace(ctx, &t.ClientTrace)
|
||||||
req = req.WithContext(ctx)
|
req = req.WithContext(ctx)
|
||||||
return ctx, req, hinjector{req}
|
return ctx, req
|
||||||
}
|
}
|
||||||
|
@ -15,15 +15,12 @@
|
|||||||
package httptrace
|
package httptrace
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/lightstep/tracecontext.go"
|
|
||||||
"github.com/lightstep/tracecontext.go/tracestate"
|
|
||||||
|
|
||||||
"go.opentelemetry.io/api/core"
|
"go.opentelemetry.io/api/core"
|
||||||
"go.opentelemetry.io/api/key"
|
"go.opentelemetry.io/api/key"
|
||||||
"go.opentelemetry.io/api/tag"
|
"go.opentelemetry.io/propagation"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -34,68 +31,21 @@ var (
|
|||||||
HostKey = key.New("http.host")
|
HostKey = key.New("http.host")
|
||||||
URLKey = key.New("http.url")
|
URLKey = key.New("http.url")
|
||||||
|
|
||||||
encoding = binary.BigEndian
|
propagator = propagation.HttpTraceContextPropagator()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Returns the Attributes, Context Tags, and SpanContext that were encoded by Inject.
|
// Returns the Attributes, Context Tags, and SpanContext that were encoded by Inject.
|
||||||
func Extract(req *http.Request) ([]core.KeyValue, []core.KeyValue, core.SpanContext) {
|
func Extract(ctx context.Context, req *http.Request) ([]core.KeyValue, []core.KeyValue, core.SpanContext) {
|
||||||
tc, err := tracecontext.FromHeaders(req.Header)
|
sc := propagator.Extract(ctx, req.Header)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, core.SpanContext{}
|
|
||||||
}
|
|
||||||
|
|
||||||
var sc core.SpanContext
|
|
||||||
sc.SpanID = encoding.Uint64(tc.TraceParent.SpanID[0:8])
|
|
||||||
sc.TraceID.High = encoding.Uint64(tc.TraceParent.TraceID[0:8])
|
|
||||||
sc.TraceID.Low = encoding.Uint64(tc.TraceParent.TraceID[8:16])
|
|
||||||
|
|
||||||
attrs := []core.KeyValue{
|
attrs := []core.KeyValue{
|
||||||
URLKey.String(req.URL.String()),
|
URLKey.String(req.URL.String()),
|
||||||
// Etc.
|
// Etc.
|
||||||
}
|
}
|
||||||
|
|
||||||
var tags []core.KeyValue
|
return attrs, nil, sc
|
||||||
|
|
||||||
for _, ts := range tc.TraceState {
|
|
||||||
if ts.Vendor != Vendor {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// TODO: max-hops, type conversion questions answered,
|
|
||||||
// case-conversion questions.
|
|
||||||
tags = append(tags, key.New(ts.Tenant).String(ts.Value))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return attrs, tags, sc
|
func Inject(ctx context.Context, req *http.Request) {
|
||||||
}
|
propagator.Inject(ctx, req.Header)
|
||||||
|
|
||||||
type hinjector struct {
|
|
||||||
*http.Request
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h hinjector) Inject(sc core.SpanContext, tags tag.Map) {
|
|
||||||
var tc tracecontext.TraceContext
|
|
||||||
var sid [8]byte
|
|
||||||
var tid [16]byte
|
|
||||||
|
|
||||||
encoding.PutUint64(sid[0:8], sc.SpanID)
|
|
||||||
encoding.PutUint64(tid[0:8], sc.TraceID.High)
|
|
||||||
encoding.PutUint64(tid[8:16], sc.TraceID.Low)
|
|
||||||
|
|
||||||
tc.TraceParent.Version = tracecontext.Version
|
|
||||||
tc.TraceParent.TraceID = tid
|
|
||||||
tc.TraceParent.SpanID = sid
|
|
||||||
tc.TraceParent.Flags.Recorded = true // Note: not implemented.
|
|
||||||
|
|
||||||
tags.Foreach(func(kv core.KeyValue) bool {
|
|
||||||
// TODO: implement MaxHops
|
|
||||||
tc.TraceState = append(tc.TraceState, tracestate.Member{
|
|
||||||
Vendor: Vendor,
|
|
||||||
Tenant: kv.Key.Name,
|
|
||||||
Value: kv.Value.Emit(),
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
tc.SetHeaders(h.Header)
|
|
||||||
}
|
}
|
||||||
|
16
propagation/doc.go
Normal file
16
propagation/doc.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2019, OpenTelemetry Authors
|
||||||
|
//
|
||||||
|
// 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 propagation contains propagators for different format and carriers.
|
||||||
|
package propagation // import "go.opentelemetry.io/propagation"
|
138
propagation/http_trace_context_propagator.go
Normal file
138
propagation/http_trace_context_propagator.go
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
// Copyright 2019, OpenTelemetry Authors
|
||||||
|
//
|
||||||
|
// 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 propagation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/api/trace"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/api/core"
|
||||||
|
apipropagation "go.opentelemetry.io/api/propagation"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
supportedVersion = 0
|
||||||
|
maxVersion = 254
|
||||||
|
traceparentHeader = "traceparent"
|
||||||
|
)
|
||||||
|
|
||||||
|
type httpTraceContextPropagator struct{}
|
||||||
|
|
||||||
|
var _ apipropagation.TextFormatPropagator = httpTraceContextPropagator{}
|
||||||
|
var traceCtxRegExp = regexp.MustCompile("^[0-9a-f]{2}-[a-f0-9]{32}-[a-f0-9]{16}-[a-f0-9]{2}-?")
|
||||||
|
|
||||||
|
func (hp httpTraceContextPropagator) Inject(ctx context.Context, supplier apipropagation.Supplier) {
|
||||||
|
sc := trace.CurrentSpan(ctx).SpanContext()
|
||||||
|
if sc.IsValid() {
|
||||||
|
h := fmt.Sprintf("%.2x-%.16x%.16x-%.16x-%.2x",
|
||||||
|
supportedVersion,
|
||||||
|
sc.TraceID.High,
|
||||||
|
sc.TraceID.Low,
|
||||||
|
sc.SpanID,
|
||||||
|
sc.TraceOptions&core.TraceOptionSampled)
|
||||||
|
supplier.Set(traceparentHeader, h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hp httpTraceContextPropagator) Extract(ctx context.Context, supplier apipropagation.Supplier) core.SpanContext {
|
||||||
|
h := supplier.Get(traceparentHeader)
|
||||||
|
if h == "" {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
h = strings.Trim(h, "-")
|
||||||
|
if !traceCtxRegExp.MatchString(h) {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
sections := strings.Split(h, "-")
|
||||||
|
if len(sections) < 4 {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sections[0]) != 2 {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
ver, err := hex.DecodeString(sections[0])
|
||||||
|
if err != nil {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
version := int(ver[0])
|
||||||
|
if version > maxVersion {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
if version == 0 && len(sections) != 4 {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sections[1]) != 32 {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := strconv.ParseUint(sections[1][0:16], 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
var sc core.SpanContext
|
||||||
|
|
||||||
|
sc.TraceID.High = result
|
||||||
|
|
||||||
|
result, err = strconv.ParseUint(sections[1][16:32], 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
sc.TraceID.Low = result
|
||||||
|
|
||||||
|
if len(sections[2]) != 16 {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
result, err = strconv.ParseUint(sections[2][0:], 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
sc.SpanID = result
|
||||||
|
|
||||||
|
if len(sections[3]) != 2 {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
opts, err := hex.DecodeString(sections[3])
|
||||||
|
if err != nil || len(opts) < 1 || (version == 0 && opts[0] > 2) {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
sc.TraceOptions = opts[0] &^ core.TraceOptionUnused
|
||||||
|
|
||||||
|
if !sc.IsValid() {
|
||||||
|
return core.EmptySpanContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
return sc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hp httpTraceContextPropagator) GetAllKeys() []string {
|
||||||
|
return []string{traceparentHeader}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HttpTraceContextPropagator creates a new text format propagator that propagates SpanContext
|
||||||
|
// in W3C TraceContext format.
|
||||||
|
func HttpTraceContextPropagator() apipropagation.TextFormatPropagator {
|
||||||
|
return httpTraceContextPropagator{}
|
||||||
|
}
|
286
propagation/http_trace_context_propagator_test.go
Normal file
286
propagation/http_trace_context_propagator_test.go
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
// Copyright 2019, OpenTelemetry Authors
|
||||||
|
//
|
||||||
|
// 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 propagation_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/api/trace"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/api/core"
|
||||||
|
mocktrace "go.opentelemetry.io/internal/trace"
|
||||||
|
"go.opentelemetry.io/propagation"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
traceID = core.TraceID{High: 0x4bf92f3577b34da6, Low: 0xa3ce929d0e0e4736}
|
||||||
|
spanID = uint64(0x00f067aa0ba902b7)
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExtractValidTraceContextFromHTTPReq(t *testing.T) {
|
||||||
|
trace.SetGlobalTracer(&mocktrace.MockTracer{})
|
||||||
|
propagator := propagation.HttpTraceContextPropagator()
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
header string
|
||||||
|
wantSc core.SpanContext
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "valid header",
|
||||||
|
header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
|
||||||
|
wantSc: core.SpanContext{
|
||||||
|
TraceID: traceID,
|
||||||
|
SpanID: spanID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid header and sampled",
|
||||||
|
header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
|
||||||
|
wantSc: core.SpanContext{
|
||||||
|
TraceID: traceID,
|
||||||
|
SpanID: spanID,
|
||||||
|
TraceOptions: core.TraceOptionSampled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "future version",
|
||||||
|
header: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
|
||||||
|
wantSc: core.SpanContext{
|
||||||
|
TraceID: traceID,
|
||||||
|
SpanID: spanID,
|
||||||
|
TraceOptions: core.TraceOptionSampled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "future options with sampled bit set",
|
||||||
|
header: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09",
|
||||||
|
wantSc: core.SpanContext{
|
||||||
|
TraceID: traceID,
|
||||||
|
SpanID: spanID,
|
||||||
|
TraceOptions: core.TraceOptionSampled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "future options with sampled bit cleared",
|
||||||
|
header: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-08",
|
||||||
|
wantSc: core.SpanContext{
|
||||||
|
TraceID: traceID,
|
||||||
|
SpanID: spanID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "future additional data",
|
||||||
|
header: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09-XYZxsf09",
|
||||||
|
wantSc: core.SpanContext{
|
||||||
|
TraceID: traceID,
|
||||||
|
SpanID: spanID,
|
||||||
|
TraceOptions: core.TraceOptionSampled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid header ending in dash",
|
||||||
|
header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01-",
|
||||||
|
wantSc: core.SpanContext{
|
||||||
|
TraceID: traceID,
|
||||||
|
SpanID: spanID,
|
||||||
|
TraceOptions: core.TraceOptionSampled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "future valid header ending in dash",
|
||||||
|
header: "01-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09-",
|
||||||
|
wantSc: core.SpanContext{
|
||||||
|
TraceID: traceID,
|
||||||
|
SpanID: spanID,
|
||||||
|
TraceOptions: core.TraceOptionSampled,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
req, _ := http.NewRequest("GET", "http://example.com", nil)
|
||||||
|
req.Header.Set("traceparent", tt.header)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
gotSc := propagator.Extract(ctx, req.Header)
|
||||||
|
if diff := cmp.Diff(gotSc, tt.wantSc); diff != "" {
|
||||||
|
t.Errorf("Extract Tracecontext: %s: -got +want %s", tt.name, diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExtractInvalidTraceContextFromHTTPReq(t *testing.T) {
|
||||||
|
trace.SetGlobalTracer(&mocktrace.MockTracer{})
|
||||||
|
propagator := propagation.HttpTraceContextPropagator()
|
||||||
|
wantSc := core.EmptySpanContext()
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
header string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "wrong version length",
|
||||||
|
header: "0000-00000000000000000000000000000000-0000000000000000-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wrong trace ID length",
|
||||||
|
header: "00-ab00000000000000000000000000000000-cd00000000000000-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wrong span ID length",
|
||||||
|
header: "00-ab000000000000000000000000000000-cd0000000000000000-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wrong trace flag length",
|
||||||
|
header: "00-ab000000000000000000000000000000-cd00000000000000-0100",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bogus version",
|
||||||
|
header: "qw-00000000000000000000000000000000-0000000000000000-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bogus trace ID",
|
||||||
|
header: "00-qw000000000000000000000000000000-cd00000000000000-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bogus span ID",
|
||||||
|
header: "00-ab000000000000000000000000000000-qw00000000000000-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bogus trace flag",
|
||||||
|
header: "00-ab000000000000000000000000000000-cd00000000000000-qw",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "upper case version",
|
||||||
|
header: "A0-00000000000000000000000000000000-0000000000000000-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "upper case trace ID",
|
||||||
|
header: "00-AB000000000000000000000000000000-cd00000000000000-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "upper case span ID",
|
||||||
|
header: "00-ab000000000000000000000000000000-CD00000000000000-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "upper case trace flag",
|
||||||
|
header: "00-ab000000000000000000000000000000-cd00000000000000-A1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "zero trace ID and span ID",
|
||||||
|
header: "00-00000000000000000000000000000000-0000000000000000-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "trace-flag unused bits set",
|
||||||
|
header: "00-ab000000000000000000000000000000-cd00000000000000-09",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "missing options",
|
||||||
|
header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty options",
|
||||||
|
header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
req, _ := http.NewRequest("GET", "http://example.com", nil)
|
||||||
|
req.Header.Set("traceparent", tt.header)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
gotSc := propagator.Extract(ctx, req.Header)
|
||||||
|
if diff := cmp.Diff(gotSc, wantSc); diff != "" {
|
||||||
|
t.Errorf("Extract Tracecontext: %s: -got +want %s", tt.name, diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInjectTraceContextToHTTPReq(t *testing.T) {
|
||||||
|
var id uint64
|
||||||
|
mockTracer := &mocktrace.MockTracer{
|
||||||
|
Sampled: false,
|
||||||
|
StartSpanId: &id,
|
||||||
|
}
|
||||||
|
propagator := propagation.HttpTraceContextPropagator()
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
sc core.SpanContext
|
||||||
|
wantHeader string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "valid spancontext, sampled",
|
||||||
|
sc: core.SpanContext{
|
||||||
|
TraceID: traceID,
|
||||||
|
SpanID: spanID,
|
||||||
|
TraceOptions: core.TraceOptionSampled,
|
||||||
|
},
|
||||||
|
wantHeader: "00-4bf92f3577b34da6a3ce929d0e0e4736-0000000000000001-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid spancontext, not sampled",
|
||||||
|
sc: core.SpanContext{
|
||||||
|
TraceID: traceID,
|
||||||
|
SpanID: spanID,
|
||||||
|
},
|
||||||
|
wantHeader: "00-4bf92f3577b34da6a3ce929d0e0e4736-0000000000000002-00",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid spancontext, with unsupported bit set in traceoption",
|
||||||
|
sc: core.SpanContext{
|
||||||
|
TraceID: traceID,
|
||||||
|
SpanID: spanID,
|
||||||
|
TraceOptions: 0xff,
|
||||||
|
},
|
||||||
|
wantHeader: "00-4bf92f3577b34da6a3ce929d0e0e4736-0000000000000003-01",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid spancontext",
|
||||||
|
sc: core.EmptySpanContext(),
|
||||||
|
wantHeader: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
req, _ := http.NewRequest("GET", "http://example.com", nil)
|
||||||
|
ctx := context.Background()
|
||||||
|
if tt.sc.IsValid() {
|
||||||
|
ctx, _ = mockTracer.Start(ctx, "inject", trace.ChildOf(tt.sc))
|
||||||
|
}
|
||||||
|
propagator.Inject(ctx, req.Header)
|
||||||
|
|
||||||
|
gotHeader := req.Header.Get("traceparent")
|
||||||
|
if diff := cmp.Diff(gotHeader, tt.wantHeader); diff != "" {
|
||||||
|
t.Errorf("Extract Tracecontext: %s: -got +want %s", tt.name, diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHttpTraceContextPropagator_GetAllKeys(t *testing.T) {
|
||||||
|
propagator := propagation.HttpTraceContextPropagator()
|
||||||
|
want := []string{"traceparent"}
|
||||||
|
got := propagator.GetAllKeys()
|
||||||
|
if diff := cmp.Diff(got, want); diff != "" {
|
||||||
|
t.Errorf("GetAllKeys: -got +want %s", diff)
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"go.opentelemetry.io/api/core"
|
"go.opentelemetry.io/api/core"
|
||||||
"go.opentelemetry.io/api/tag"
|
|
||||||
apitrace "go.opentelemetry.io/api/trace"
|
apitrace "go.opentelemetry.io/api/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -102,7 +101,3 @@ func (tr *tracer) WithComponent(component string) apitrace.Tracer {
|
|||||||
tr.component = component
|
tr.component = component
|
||||||
return tr
|
return tr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *tracer) Inject(ctx context.Context, span apitrace.Span, injector apitrace.Injector) {
|
|
||||||
injector.Inject(span.SpanContext(), tag.NewEmptyMap())
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user