Skip to content

Commit d3b1280

Browse files
dashpoleMrAliaspellared
authored
Add Passthrough example (open-telemetry#1912)
* Add passthrough example * Update example/passthrough/handler/handler.go Co-authored-by: Tyler Yahn <[email protected]> * Update example/passthrough/README.md Co-authored-by: Tyler Yahn <[email protected]> * Apply suggestions from code review Co-authored-by: Robert Pająk <[email protected]> Co-authored-by: Tyler Yahn <[email protected]> Co-authored-by: Robert Pająk <[email protected]>
1 parent f06cace commit d3b1280

File tree

30 files changed

+339
-0
lines changed

30 files changed

+339
-0
lines changed

.github/dependabot.yml

+10
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,16 @@ updates:
9696
schedule:
9797
day: sunday
9898
interval: weekly
99+
-
100+
package-ecosystem: gomod
101+
directory: /example/passthrough
102+
labels:
103+
- dependencies
104+
- go
105+
- "Skip Changelog"
106+
schedule:
107+
day: sunday
108+
interval: weekly
99109
-
100110
package-ecosystem: gomod
101111
directory: /example/prometheus

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ gen/
1313
/example/jaeger/jaeger
1414
/example/namedtracer/namedtracer
1515
/example/opencensus/opencensus
16+
/example/passthrough/passthrough
1617
/example/prometheus/prometheus
1718
/example/prom-collector/prom-collector
1819
/example/zipkin/zipkin

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
2525
- The `SpanStub` type and its associated functions were added to the `go.opentelemetry.io/otel/sdk/trace/tracetest` package.
2626
This type can be used as a testing replacement for the `SpanSnapshot` that was removed from the `go.opentelemetry.io/otel/sdk/trace` package. (#1873)
2727
- Adds support for scheme in `OTEL_EXPORTER_OTLP_ENDPOINT` according to the spec. (#1886)
28+
- An example of using OpenTelemetry Go as a trace context forwarder. (#1912)
2829

2930
### Changed
3031

bridge/opencensus/go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
5555
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric
5656

5757
replace go.opentelemetry.io/otel/trace => ../../trace
58+
59+
replace go.opentelemetry.io/otel/example/passthrough => ../../example/passthrough

bridge/opentracing/go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
5151
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric
5252

5353
replace go.opentelemetry.io/otel/trace => ../../trace
54+
55+
replace go.opentelemetry.io/otel/example/passthrough => ../../example/passthrough

example/jaeger/go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
5151
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric
5252

5353
replace go.opentelemetry.io/otel/trace => ../../trace
54+
55+
replace go.opentelemetry.io/otel/example/passthrough => ../passthrough

example/namedtracer/go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
5252
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric
5353

5454
replace go.opentelemetry.io/otel/trace => ../../trace
55+
56+
replace go.opentelemetry.io/otel/example/passthrough => ../passthrough

example/opencensus/go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
5353
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric
5454

5555
replace go.opentelemetry.io/otel/trace => ../../trace
56+
57+
replace go.opentelemetry.io/otel/example/passthrough => ../passthrough

example/otel-collector/go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
5555
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric
5656

5757
replace go.opentelemetry.io/otel/trace => ../../trace
58+
59+
replace go.opentelemetry.io/otel/example/passthrough => ../passthrough

example/passthrough/README.md

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# "Passthrough" setup for OpenTelemetry
2+
3+
Some Go programs may wish to propagate context without recording spans. To do this in OpenTelemetry, simply install `TextMapPropagators`, but do not install a TracerProvider using the SDK. This works because the default TracerProvider implementation returns a "Non-Recording" span that keeps the context of the caller but does not record spans.
4+
5+
For example, when you initialize your global settings, the following will propagate context without recording spans:
6+
7+
```golang
8+
// Setup Propagators only
9+
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
10+
```
11+
12+
But the following will propagate context _and_ create new, potentially recorded spans:
13+
14+
```golang
15+
// Setup SDK
16+
exp, _ := stdout.NewExporter(stdout.WithPrettyPrint())
17+
tp = sdktrace.NewTracerProvider(
18+
sdktrace.WithBatcher(exp),
19+
)
20+
otel.SetTracerProvider(tp)
21+
// Setup Propagators
22+
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
23+
```
24+
25+
## The Demo
26+
27+
The demo has the following call structure:
28+
29+
`Outer -> Passthrough -> Inner`
30+
31+
If all components had both an SDK and propagators registered, we would expect the trace to look like:
32+
33+
```
34+
|-------outer---------|
35+
|-Passthrough recv-|
36+
|Passthrough send|
37+
|---inner---|
38+
```
39+
40+
However, in this demo, only the outer and inner have TracerProvider backed by the SDK. All components have Propagators set. In this case, we expect to see:
41+
42+
```
43+
|-------outer---------|
44+
|---inner---|
45+
```

example/passthrough/go.mod

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
module go.opentelemetry.io/otel/example/passthrough
2+
3+
go 1.16
4+
5+
require (
6+
go.opentelemetry.io/otel v0.20.0
7+
go.opentelemetry.io/otel/exporters/stdout v0.20.0
8+
go.opentelemetry.io/otel/sdk v0.20.0
9+
go.opentelemetry.io/otel/trace v0.20.0
10+
)
11+
12+
replace (
13+
go.opentelemetry.io/otel => ../..
14+
go.opentelemetry.io/otel/exporters/stdout => ../../exporters/stdout
15+
go.opentelemetry.io/otel/sdk => ../../sdk
16+
go.opentelemetry.io/otel/trace => ../../trace
17+
)
18+
19+
replace go.opentelemetry.io/otel/bridge/opencensus => ../../bridge/opencensus
20+
21+
replace go.opentelemetry.io/otel/bridge/opentracing => ../../bridge/opentracing
22+
23+
replace go.opentelemetry.io/otel/example/jaeger => ../jaeger
24+
25+
replace go.opentelemetry.io/otel/example/namedtracer => ../namedtracer
26+
27+
replace go.opentelemetry.io/otel/example/opencensus => ../opencensus
28+
29+
replace go.opentelemetry.io/otel/example/otel-collector => ../otel-collector
30+
31+
replace go.opentelemetry.io/otel/example/passthrough => ./
32+
33+
replace go.opentelemetry.io/otel/example/prom-collector => ../prom-collector
34+
35+
replace go.opentelemetry.io/otel/example/prometheus => ../prometheus
36+
37+
replace go.opentelemetry.io/otel/example/zipkin => ../zipkin
38+
39+
replace go.opentelemetry.io/otel/exporters/metric/prometheus => ../../exporters/metric/prometheus
40+
41+
replace go.opentelemetry.io/otel/exporters/otlp => ../../exporters/otlp
42+
43+
replace go.opentelemetry.io/otel/exporters/trace/jaeger => ../../exporters/trace/jaeger
44+
45+
replace go.opentelemetry.io/otel/exporters/trace/zipkin => ../../exporters/trace/zipkin
46+
47+
replace go.opentelemetry.io/otel/internal/tools => ../../internal/tools
48+
49+
replace go.opentelemetry.io/otel/metric => ../../metric
50+
51+
replace go.opentelemetry.io/otel/oteltest => ../../oteltest
52+
53+
replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
54+
55+
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric
56+
57+
replace go.opentelemetry.io/otel/sdk/trace => ../../sdk/trace

example/passthrough/go.sum

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
2+
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
3+
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
4+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
6+
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
7+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
8+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
9+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
10+
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
11+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
12+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
13+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
14+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
15+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
16+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
17+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright The OpenTelemetry Authors
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 handler
16+
17+
import (
18+
"context"
19+
"log"
20+
"net/http"
21+
"time"
22+
23+
"go.opentelemetry.io/otel"
24+
"go.opentelemetry.io/otel/propagation"
25+
"go.opentelemetry.io/otel/trace"
26+
)
27+
28+
// Handler is a minimal implementation of the handler and client from
29+
// go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp for demonstration purposes.
30+
// It handles an incoming http request, and makes an outgoing http request.
31+
type Handler struct {
32+
propagators propagation.TextMapPropagator
33+
tracer trace.Tracer
34+
next func(r *http.Request)
35+
}
36+
37+
func New(next func(r *http.Request)) *Handler {
38+
// Like most instrumentation packages, this handler defaults to using the
39+
// global progatators and tracer providers.
40+
return &Handler{
41+
propagators: otel.GetTextMapPropagator(),
42+
tracer: otel.Tracer("examples/passthrough/handler"),
43+
next: next,
44+
}
45+
}
46+
47+
// HandleHTTPReq mimics what an instrumented http server does
48+
func (h *Handler) HandleHTTPReq(r *http.Request) {
49+
ctx := h.propagators.Extract(r.Context(), propagation.HeaderCarrier(r.Header))
50+
var span trace.Span
51+
log.Println("The \"handle passthrough request\" span should NOT be recorded, because it is recorded by a TracerProvider not backed by the SDK.")
52+
ctx, span = h.tracer.Start(ctx, "handle passthrough request")
53+
defer span.End()
54+
55+
// Pretend to do work
56+
time.Sleep(time.Second)
57+
58+
h.makeOutgoingRequest(ctx)
59+
}
60+
61+
// makeOutgoingRequest mimics what an instrumented http client does
62+
func (h *Handler) makeOutgoingRequest(ctx context.Context) {
63+
// make a new http request
64+
r, err := http.NewRequest("", "", nil)
65+
if err != nil {
66+
panic(err)
67+
}
68+
69+
log.Println("The \"make outgoing request from passthrough\" span should NOT be recorded, because it is recorded by a TracerProvider not backed by the SDK.")
70+
ctx, span := h.tracer.Start(ctx, "make outgoing request from passthrough")
71+
defer span.End()
72+
r = r.WithContext(ctx)
73+
h.propagators.Inject(ctx, propagation.HeaderCarrier(r.Header))
74+
h.next(r)
75+
}

example/passthrough/main.go

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright The OpenTelemetry Authors
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 main
16+
17+
import (
18+
"context"
19+
"log"
20+
"net/http"
21+
"time"
22+
23+
"go.opentelemetry.io/otel"
24+
"go.opentelemetry.io/otel/example/passthrough/handler"
25+
"go.opentelemetry.io/otel/exporters/stdout"
26+
"go.opentelemetry.io/otel/propagation"
27+
sdktrace "go.opentelemetry.io/otel/sdk/trace"
28+
"go.opentelemetry.io/otel/trace"
29+
)
30+
31+
func main() {
32+
ctx := context.Background()
33+
34+
initPassthroughGlobals()
35+
tp := nonGlobalTracer()
36+
defer func() { _ = tp.Shutdown(ctx) }()
37+
38+
// make an initial http request
39+
r, err := http.NewRequest("", "", nil)
40+
if err != nil {
41+
panic(err)
42+
}
43+
44+
// This is roughly what an instrumented http client does.
45+
log.Println("The \"make outer request\" span should be recorded, because it is recorded with a Tracer from the SDK TracerProvider")
46+
var span trace.Span
47+
ctx, span = tp.Tracer("example/passthrough/outer").Start(ctx, "make outer request")
48+
defer span.End()
49+
r = r.WithContext(ctx)
50+
otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(r.Header))
51+
52+
backendFunc := func(r *http.Request) {
53+
// This is roughly what an instrumented http server does.
54+
ctx := otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header))
55+
log.Println("The \"handle inner request\" span should be recorded, because it is recorded with a Tracer from the SDK TracerProvider")
56+
_, span := tp.Tracer("example/passthrough/inner").Start(ctx, "handle inner request")
57+
defer span.End()
58+
59+
// Do "backend work"
60+
time.Sleep(time.Second)
61+
}
62+
// This handler will be a passthrough, since we didn't set a global TracerProvider
63+
passthroughHandler := handler.New(backendFunc)
64+
passthroughHandler.HandleHTTPReq(r)
65+
}
66+
67+
func initPassthroughGlobals() {
68+
// We explicitly DO NOT set the global TracerProvider using otel.SetTracerProvider().
69+
// The unset TracerProvider returns a "non-recording" span, but still passes through context.
70+
log.Println("Register a global TextMapPropagator, but do not register a global TracerProvider to be in \"passthrough\" mode.")
71+
log.Println("The \"passthrough\" mode propagates the TraceContext and Baggage, but does not record spans.")
72+
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
73+
}
74+
75+
// nonGlobalTracer creates a trace provider instance for testing, but doesn't
76+
// set it as the global tracer provider
77+
func nonGlobalTracer() *sdktrace.TracerProvider {
78+
var err error
79+
exp, err := stdout.NewExporter(stdout.WithPrettyPrint())
80+
if err != nil {
81+
log.Panicf("failed to initialize stdout exporter %v\n", err)
82+
}
83+
bsp := sdktrace.NewBatchSpanProcessor(exp)
84+
tp := sdktrace.NewTracerProvider(
85+
sdktrace.WithSampler(sdktrace.AlwaysSample()),
86+
sdktrace.WithSpanProcessor(bsp),
87+
)
88+
return tp
89+
}

example/prom-collector/go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
5454
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric
5555

5656
replace go.opentelemetry.io/otel/trace => ../../trace
57+
58+
replace go.opentelemetry.io/otel/example/passthrough => ../passthrough

example/prometheus/go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
5151
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric
5252

5353
replace go.opentelemetry.io/otel/trace => ../../trace
54+
55+
replace go.opentelemetry.io/otel/example/passthrough => ../passthrough

example/zipkin/go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
5252
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric
5353

5454
replace go.opentelemetry.io/otel/trace => ../../trace
55+
56+
replace go.opentelemetry.io/otel/example/passthrough => ../passthrough

exporters/metric/prometheus/go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../../sdk/export/metric
5656
replace go.opentelemetry.io/otel/sdk/metric => ../../../sdk/metric
5757

5858
replace go.opentelemetry.io/otel/trace => ../../../trace
59+
60+
replace go.opentelemetry.io/otel/example/passthrough => ../../../example/passthrough

exporters/otlp/go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
6262
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric
6363

6464
replace go.opentelemetry.io/otel/trace => ../../trace
65+
66+
replace go.opentelemetry.io/otel/example/passthrough => ../../example/passthrough

exporters/stdout/go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
5656
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric
5757

5858
replace go.opentelemetry.io/otel/trace => ../../trace
59+
60+
replace go.opentelemetry.io/otel/example/passthrough => ../../example/passthrough

exporters/trace/jaeger/go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../../sdk/export/metric
5454
replace go.opentelemetry.io/otel/sdk/metric => ../../../sdk/metric
5555

5656
replace go.opentelemetry.io/otel/trace => ../../../trace
57+
58+
replace go.opentelemetry.io/otel/example/passthrough => ../../../example/passthrough

0 commit comments

Comments
 (0)