Skip to content

Commit

Permalink
Add passthrough example
Browse files Browse the repository at this point in the history
  • Loading branch information
dashpole committed May 13, 2021
1 parent fb88e92 commit ec01f5b
Show file tree
Hide file tree
Showing 30 changed files with 339 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Expand Up @@ -96,6 +96,16 @@ updates:
schedule:
day: sunday
interval: weekly
-
package-ecosystem: gomod
directory: /example/passthrough
labels:
- dependencies
- go
- "Skip Changelog"
schedule:
day: sunday
interval: weekly
-
package-ecosystem: gomod
directory: /example/prometheus
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -13,6 +13,7 @@ gen/
/example/jaeger/jaeger
/example/namedtracer/namedtracer
/example/opencensus/opencensus
/example/passthrough/passthrough
/example/prometheus/prometheus
/example/prom-collector/prom-collector
/example/zipkin/zipkin
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -25,6 +25,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- The `SpanStub` type and its associated functions were added to the `go.opentelemetry.io/otel/sdk/trace/tracetest` package.
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)
- Adds support for scheme in `OTEL_EXPORTER_OTLP_ENDPOINT` according to the spec. (#1886)
- An example of using OpenTelemetry Go as a trace context forwarder. (#1912)

### Changed

Expand Down
2 changes: 2 additions & 0 deletions bridge/opencensus/go.mod
Expand Up @@ -55,3 +55,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric

replace go.opentelemetry.io/otel/trace => ../../trace

replace go.opentelemetry.io/otel/example/passthrough => ../../example/passthrough
2 changes: 2 additions & 0 deletions bridge/opentracing/go.mod
Expand Up @@ -51,3 +51,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric

replace go.opentelemetry.io/otel/trace => ../../trace

replace go.opentelemetry.io/otel/example/passthrough => ../../example/passthrough
2 changes: 2 additions & 0 deletions example/jaeger/go.mod
Expand Up @@ -51,3 +51,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric

replace go.opentelemetry.io/otel/trace => ../../trace

replace go.opentelemetry.io/otel/example/passthrough => ../passthrough
2 changes: 2 additions & 0 deletions example/namedtracer/go.mod
Expand Up @@ -52,3 +52,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric

replace go.opentelemetry.io/otel/trace => ../../trace

replace go.opentelemetry.io/otel/example/passthrough => ../passthrough
2 changes: 2 additions & 0 deletions example/opencensus/go.mod
Expand Up @@ -53,3 +53,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric

replace go.opentelemetry.io/otel/trace => ../../trace

replace go.opentelemetry.io/otel/example/passthrough => ../passthrough
2 changes: 2 additions & 0 deletions example/otel-collector/go.mod
Expand Up @@ -55,3 +55,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric

replace go.opentelemetry.io/otel/trace => ../../trace

replace go.opentelemetry.io/otel/example/passthrough => ../passthrough
45 changes: 45 additions & 0 deletions example/passthrough/README.md
@@ -0,0 +1,45 @@
# "Passthrough" setup for OpenTelemetry

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.

For example, when you initialize your global settings, the following will propagate context without recording spans:

```golang
// Setup Propagators only
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
```

But the following will propagate context _and_ create new, potentially recorded spans:

```golang
// Setup SDK
exp, _ := stdout.NewExporter(stdout.WithPrettyPrint())
tp = sdktrace.NewTracerProvider(
sdktrace.WithSpanProcessor(sdktrace.NewBatchSpanProcessor(exp)),
)
otel.SetTracerProvider(tp)
// Setup Propagators
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
```

## The Demo

The demo has the following call structure:

`Outer -> Passthrough -> Inner`

If all components had both an SDK and propagators registered, we would expect the trace to look like:

```
|-------outer---------|
|-Passthrough recv-|
|Passthrough send|
|---inner---|
```

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:

```
|-------outer---------|
|---inner---|
```
57 changes: 57 additions & 0 deletions example/passthrough/go.mod
@@ -0,0 +1,57 @@
module go.opentelemetry.io/otel/example/passthrough

go 1.16

require (
go.opentelemetry.io/otel v0.20.0
go.opentelemetry.io/otel/exporters/stdout v0.20.0
go.opentelemetry.io/otel/sdk v0.20.0
go.opentelemetry.io/otel/trace v0.20.0
)

replace (
go.opentelemetry.io/otel => ../..
go.opentelemetry.io/otel/exporters/stdout => ../../exporters/stdout
go.opentelemetry.io/otel/sdk => ../../sdk
go.opentelemetry.io/otel/trace => ../../trace
)

replace go.opentelemetry.io/otel/bridge/opencensus => ../../bridge/opencensus

replace go.opentelemetry.io/otel/bridge/opentracing => ../../bridge/opentracing

replace go.opentelemetry.io/otel/example/jaeger => ../jaeger

replace go.opentelemetry.io/otel/example/namedtracer => ../namedtracer

replace go.opentelemetry.io/otel/example/opencensus => ../opencensus

replace go.opentelemetry.io/otel/example/otel-collector => ../otel-collector

replace go.opentelemetry.io/otel/example/passthrough => ./

replace go.opentelemetry.io/otel/example/prom-collector => ../prom-collector

replace go.opentelemetry.io/otel/example/prometheus => ../prometheus

replace go.opentelemetry.io/otel/example/zipkin => ../zipkin

replace go.opentelemetry.io/otel/exporters/metric/prometheus => ../../exporters/metric/prometheus

replace go.opentelemetry.io/otel/exporters/otlp => ../../exporters/otlp

replace go.opentelemetry.io/otel/exporters/trace/jaeger => ../../exporters/trace/jaeger

replace go.opentelemetry.io/otel/exporters/trace/zipkin => ../../exporters/trace/zipkin

replace go.opentelemetry.io/otel/internal/tools => ../../internal/tools

replace go.opentelemetry.io/otel/metric => ../../metric

replace go.opentelemetry.io/otel/oteltest => ../../oteltest

replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric

replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric

replace go.opentelemetry.io/otel/sdk/trace => ../../sdk/trace
17 changes: 17 additions & 0 deletions example/passthrough/go.sum
@@ -0,0 +1,17 @@
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
75 changes: 75 additions & 0 deletions example/passthrough/handler/handler.go
@@ -0,0 +1,75 @@
// Copyright The 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 handler

import (
"context"
"log"
"net/http"
"time"

"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
)

// handler is a minimal implementation of the handler and client from
// go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp for demonstration purposes.
// It handles an incoming http request, and makes an outgoing http request.
type Handler struct {
propagators propagation.TextMapPropagator
tracer trace.Tracer
next func(r *http.Request)
}

func New(next func(r *http.Request)) *Handler {
// Like most instrumentation packages, this handler defaults to using the
// global progatators and tracer providers.
return &Handler{
propagators: otel.GetTextMapPropagator(),
tracer: otel.GetTracerProvider().Tracer("examples/passthrough/handler"),
next: next,
}
}

// HandleHTTPReq mimics what an instrumented http server does
func (h *Handler) HandleHTTPReq(r *http.Request) {
ctx := h.propagators.Extract(r.Context(), propagation.HeaderCarrier(r.Header))
var span trace.Span
log.Println("The \"handle passthrough request\" span should NOT be recorded, because it is recorded by a TracerProvider not backed by the SDK.")
ctx, span = h.tracer.Start(ctx, "handle passthrough request")
defer span.End()

// Pretend to do work
time.Sleep(time.Second)

h.makeOutgoingRequest(ctx)
}

// makeOutgoingRequest mimics what an instrumented http client does
func (h *Handler) makeOutgoingRequest(ctx context.Context) {
// make a new http request
r, err := http.NewRequest("", "", nil)
if err != nil {
panic(err)
}

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.")
ctx, span := h.tracer.Start(ctx, "make outgoing request from passthrough")
defer span.End()
r = r.WithContext(ctx)
h.propagators.Inject(ctx, propagation.HeaderCarrier(r.Header))
h.next(r)
}
89 changes: 89 additions & 0 deletions example/passthrough/main.go
@@ -0,0 +1,89 @@
// Copyright The 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 main

import (
"context"
"log"
"net/http"
"time"

"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/example/passthrough/handler"
"go.opentelemetry.io/otel/exporters/stdout"
"go.opentelemetry.io/otel/propagation"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
)

func main() {
ctx := context.Background()

initPassthroughGlobals()
tp := nonGlobalTracer()
defer func() { _ = tp.Shutdown(ctx) }()

// make an initial http request
r, err := http.NewRequest("", "", nil)
if err != nil {
panic(err)
}

// This is roughly what an instrumented http client does.
log.Println("The \"make outer request\" span should be recorded, because it is recorded with a Tracer from the SDK TracerProvider")
var span trace.Span
ctx, span = tp.Tracer("example/passthrough/outer").Start(ctx, "make outer request")
defer span.End()
r = r.WithContext(ctx)
otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(r.Header))

backendFunc := func(r *http.Request) {
// This is roughly what an instrumented http server does.
ctx := otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header))
log.Println("The \"handle inner request\" span should be recorded, because it is recorded with a Tracer from the SDK TracerProvider")
_, span := tp.Tracer("example/passthrough/inner").Start(ctx, "handle inner request")
defer span.End()

// Do "backend work"
time.Sleep(time.Second)
}
// This handler will be a passthrough, since we didn't set a global TracerProvider
passthroughHandler := handler.New(backendFunc)
passthroughHandler.HandleHTTPReq(r)
}

func initPassthroughGlobals() {
// We explicitly DO NOT set the global TracerProvider using otel.SetTracerProvider().
// The unset TracerProvider returns a "non-recording" span, but still passes through context.
log.Println("Register a global TextMapPropagator, but do not register a global TracerProvider to be in \"passthrough\" mode.")
log.Println("The \"passthrough\" mode propagates the TraceContext and Baggage, but does not record spans.")
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
}

// nonGlobalTracer creates a trace provider instance for testing, but doesn't
// set it as the global tracer provider
func nonGlobalTracer() *sdktrace.TracerProvider {
var err error
exp, err := stdout.NewExporter(stdout.WithPrettyPrint())
if err != nil {
log.Panicf("failed to initialize stdout exporter %v\n", err)
}
bsp := sdktrace.NewBatchSpanProcessor(exp)
tp := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithSpanProcessor(bsp),
)
return tp
}
2 changes: 2 additions & 0 deletions example/prom-collector/go.mod
Expand Up @@ -54,3 +54,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric

replace go.opentelemetry.io/otel/trace => ../../trace

replace go.opentelemetry.io/otel/example/passthrough => ../passthrough
2 changes: 2 additions & 0 deletions example/prometheus/go.mod
Expand Up @@ -51,3 +51,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric

replace go.opentelemetry.io/otel/trace => ../../trace

replace go.opentelemetry.io/otel/example/passthrough => ../passthrough
2 changes: 2 additions & 0 deletions example/zipkin/go.mod
Expand Up @@ -52,3 +52,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric

replace go.opentelemetry.io/otel/trace => ../../trace

replace go.opentelemetry.io/otel/example/passthrough => ../passthrough
2 changes: 2 additions & 0 deletions exporters/metric/prometheus/go.mod
Expand Up @@ -56,3 +56,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../../sdk/export/metric
replace go.opentelemetry.io/otel/sdk/metric => ../../../sdk/metric

replace go.opentelemetry.io/otel/trace => ../../../trace

replace go.opentelemetry.io/otel/example/passthrough => ../../../example/passthrough
2 changes: 2 additions & 0 deletions exporters/otlp/go.mod
Expand Up @@ -62,3 +62,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric

replace go.opentelemetry.io/otel/trace => ../../trace

replace go.opentelemetry.io/otel/example/passthrough => ../../example/passthrough
2 changes: 2 additions & 0 deletions exporters/stdout/go.mod
Expand Up @@ -56,3 +56,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../sdk/export/metric
replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric

replace go.opentelemetry.io/otel/trace => ../../trace

replace go.opentelemetry.io/otel/example/passthrough => ../../example/passthrough
2 changes: 2 additions & 0 deletions exporters/trace/jaeger/go.mod
Expand Up @@ -54,3 +54,5 @@ replace go.opentelemetry.io/otel/sdk/export/metric => ../../../sdk/export/metric
replace go.opentelemetry.io/otel/sdk/metric => ../../../sdk/metric

replace go.opentelemetry.io/otel/trace => ../../../trace

replace go.opentelemetry.io/otel/example/passthrough => ../../../example/passthrough

0 comments on commit ec01f5b

Please sign in to comment.