Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add autoprop package to provide configuration of propagators with useful defaults and envar support #2258

Merged
merged 28 commits into from Jun 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6db714a
Add autoprop module
MrAlias May 3, 2022
6f771c3
Add example tests
MrAlias May 3, 2022
c334328
Add unit tests for registry.go
MrAlias May 3, 2022
b86fa71
Add unit test for NewTextMapPropagator
MrAlias May 3, 2022
db77676
Add NewTextMapPropagator unit tests
MrAlias May 3, 2022
67fb8ec
Fix RegisterTextMapPropagator func name
MrAlias May 3, 2022
3aab5aa
Fix lint
MrAlias May 3, 2022
1055a5c
Go import lint fix
MrAlias May 3, 2022
492a700
Add dependabot entry
MrAlias May 3, 2022
9201c4b
Add change to the changelog
MrAlias May 3, 2022
999aa9c
Add autoprop to versions
MrAlias May 3, 2022
a45b5de
Add setenv test func to support Go 1.16
MrAlias May 3, 2022
7521e6b
Fix spelling error in comment
MrAlias May 3, 2022
037664e
Rename registry index field to names
MrAlias May 4, 2022
a92287d
Remove interface assertion
MrAlias May 4, 2022
d6f635e
Merge branch 'main' into autoprop
MrAlias May 18, 2022
3066c92
Merge branch 'main' into autoprop
MrAlias May 24, 2022
79ada0b
Fix lint
MrAlias May 24, 2022
d5d03c6
Merge branch 'main' into autoprop
MrAlias May 24, 2022
d5b47c2
Merge branch 'main' into autoprop
MrAlias May 24, 2022
f1c9e3d
Update RegisterTextMapPropagator docs
MrAlias May 25, 2022
dd600fe
Remove compile time assertion and test of impl
MrAlias May 25, 2022
d107b46
Merge branch 'main' into autoprop
MrAlias May 26, 2022
12a4952
Upgrade to Go 1.17 as min supported version
MrAlias May 26, 2022
0b37e5b
Use T.Setenv instead of own setenv func
MrAlias May 26, 2022
1f54df0
Panic on duplicate prop register
MrAlias May 26, 2022
0e495e2
Check errs in registry_test
MrAlias May 31, 2022
ded3cb7
Merge branch 'main' into autoprop
MrAlias Jun 2, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/dependabot.yml
Expand Up @@ -532,6 +532,15 @@ updates:
schedule:
interval: weekly
day: sunday
- package-ecosystem: gomod
directory: /propagators/autoprop
labels:
- dependencies
- go
- Skip Changelog
schedule:
interval: weekly
day: sunday
- package-ecosystem: gomod
directory: /propagators/aws
labels:
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

## [Unreleased]

### Added

- The `go.opentelemetry.io/contrib/propagators/autoprop` package to provide configuration of propagators with useful defaults and envar support. (#2258)

## [1.7.0/0.32.0] - 2022-04-28

### Added
Expand Down
23 changes: 23 additions & 0 deletions propagators/autoprop/doc.go
@@ -0,0 +1,23 @@
// 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 autoprop provides an OpenTelemetry TextMapPropagator creation
// function. The OpenTelemetry specification states that the default
// TextMapPropagator needs to be a no-operation implementation. The
// opentelemetry-go project adheres to this requirement. However, for systems
// that perform propagation this default is not ideal. This package provides a
// TextMapPropagator with useful defaults (a combined TraceContext and Baggage
// TextMapPropagator), and supports environment overrides using the
// OTEL_PROPAGATORS environment variable.
package autoprop // import "go.opentelemetry.io/contrib/propagators/autoprop"
84 changes: 84 additions & 0 deletions propagators/autoprop/example_test.go
@@ -0,0 +1,84 @@
// 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 autoprop_test

import (
"fmt"
"os"
"sort"

"go.opentelemetry.io/contrib/propagators/autoprop"
"go.opentelemetry.io/contrib/propagators/b3"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
)

func ExampleNewTextMapPropagator() {
// NewTextMapPropagator returns a TraceContext and Baggage propagator by
// default. The response of this function can be directly registered with
// the go.opentelemetry.io/otel package.
otel.SetTextMapPropagator(autoprop.NewTextMapPropagator())

fields := otel.GetTextMapPropagator().Fields()
sort.Strings(fields)
fmt.Println(fields)
// Output: [baggage traceparent tracestate]
}

func ExampleNewTextMapPropagator_arguments() {
// NewTextMapPropagator behaves the same as the
// NewCompositeTextMapPropagator function in the
// go.opentelemetry.io/otel/propagation package when TextMapPropagator are
// passed as arguments.
fields := autoprop.NewTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{},
b3.New(),
).Fields()
sort.Strings(fields)
fmt.Println(fields)
// Output: [baggage traceparent tracestate x-b3-flags x-b3-sampled x-b3-spanid x-b3-traceid]
}

func ExampleNewTextMapPropagator_environment() {
// Propagators set for the OTEL_PROPAGATORS environment variable take
// precedence and will override any arguments passed to
// NewTextMapPropagator.
_ = os.Setenv("OTEL_PROPAGATORS", "b3,baggage")
MrAlias marked this conversation as resolved.
Show resolved Hide resolved

// Returns only a B3 and Baggage TextMapPropagator (i.e. does not include
// TraceContext).
fields := autoprop.NewTextMapPropagator(propagation.TraceContext{}).Fields()
sort.Strings(fields)
fmt.Println(fields)
// Output: [baggage x-b3-flags x-b3-sampled x-b3-spanid x-b3-traceid]
}

type myTextMapPropagator struct{ propagation.TextMapPropagator }

func (myTextMapPropagator) Fields() []string {
return []string{"my-header-val"}
}

func ExampleRegisterTextMapPropagator() {
// To use your own or a 3rd-party exporter via the OTEL_PROPAGATORS
// environment variable, it needs to be registered prior to calling
// NewTextMapPropagator.
autoprop.RegisterTextMapPropagator("custom-prop", myTextMapPropagator{})

_ = os.Setenv("OTEL_PROPAGATORS", "custom-prop")
fmt.Println(autoprop.NewTextMapPropagator().Fields())
// Output: [my-header-val]
}
25 changes: 25 additions & 0 deletions propagators/autoprop/go.mod
@@ -0,0 +1,25 @@
module go.opentelemetry.io/contrib/propagators/autoprop

go 1.17

require (
github.com/stretchr/testify v1.7.1
go.opentelemetry.io/contrib/propagators/aws v1.7.0
go.opentelemetry.io/contrib/propagators/b3 v1.7.0
go.opentelemetry.io/contrib/propagators/jaeger v1.7.0
go.opentelemetry.io/contrib/propagators/ot v1.7.0
go.opentelemetry.io/otel v1.7.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.opentelemetry.io/otel/sdk v1.7.0 // indirect
go.opentelemetry.io/otel/trace v1.7.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
43 changes: 43 additions & 0 deletions propagators/autoprop/go.sum
@@ -0,0 +1,43 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.opentelemetry.io/contrib/propagators/aws v1.7.0 h1:hzLtX+K4YhsrBabA35uBYxCENb5rS/9Z9X8MToTlA3k=
go.opentelemetry.io/contrib/propagators/aws v1.7.0/go.mod h1:h/ql5T6e1XLRFplWNNdzLHp8eb0dkBu+xYOCYxerh0Q=
go.opentelemetry.io/contrib/propagators/b3 v1.7.0 h1:oRAenUhj+GFttfIp3gj7HYVzBhPOHgq/dWPDSmLCXSY=
go.opentelemetry.io/contrib/propagators/b3 v1.7.0/go.mod h1:gXx7AhL4xXCF42gpm9dQvdohoDa2qeyEx4eIIxqK+h4=
go.opentelemetry.io/contrib/propagators/jaeger v1.7.0 h1:x2mXKtONfOJFfNFSx4QXFx1fms6bKIPVvWvgdiaPdRI=
go.opentelemetry.io/contrib/propagators/jaeger v1.7.0/go.mod h1:kt2lNImfxV6dETRsDCENd6jU6G0mPRS+P0qlNuvtkTE=
go.opentelemetry.io/contrib/propagators/ot v1.7.0 h1:KPPToDRxyY/HI3qD4RqwWRbaQ65RIpF8uKWDqWkFHDA=
go.opentelemetry.io/contrib/propagators/ot v1.7.0/go.mod h1:5qxBZR730yb71uXc3bazxt2Si8o8LQK3iJTnSLca/BU=
go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM=
go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0=
go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU=
go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o=
go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
129 changes: 129 additions & 0 deletions propagators/autoprop/propagator.go
@@ -0,0 +1,129 @@
// 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 autoprop // import "go.opentelemetry.io/contrib/propagators/autoprop"

import (
"errors"
"fmt"
"os"
"strings"

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

// otelPropagatorsEnvKey is the environment variable name identifying
// propagators to use.
const otelPropagatorsEnvKey = "OTEL_PROPAGATORS"

// NewTextMapPropagator returns a new TextMapPropagator composited by props or
// one defined by the OTEL_PROPAGATORS environment variable. The
// TextMapPropagator defined by OTEL_PROPAGATORS, if set, will take precedence
// to the once composited by props.
//
// The propagators supported with the OTEL_PROPAGATORS environment variable by
// default are: tracecontext, baggage, b3, b3multi, jaeger, xray, ottrace, and
dashpole marked this conversation as resolved.
Show resolved Hide resolved
// none. Each of these values, and their combination, are supported in
// conformance with the OpenTelemetry specification. See
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#general-sdk-configuration
// for more information.
//
// The supported environment variable propagators can be extended to include
// custom 3rd-party TextMapPropagator. See the RegisterTextMapPropagator
// function for more information.
//
// If OTEL_PROPAGATORS is not defined and props is no provided, the returned
// TextMapPropagator will be a composite of the TraceContext and Baggage
// propagators.
func NewTextMapPropagator(props ...propagation.TextMapPropagator) propagation.TextMapPropagator {
// Environment variable defined propagator has precedence over arguments.
envProp, err := parseEnv()
if err != nil {
// Communicate to the user their supplied value will not be used.
otel.Handle(err)
}
if envProp != nil {
return envProp
}

switch len(props) {
case 0:
// Default to TraceContext and Baggage.
return propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{}, propagation.Baggage{},
)
case 1:
// Do not add overhead with a composite propagator wrapping a single
// propagator, return it directly.
return props[0]
default:
return propagation.NewCompositeTextMapPropagator(props...)
}
}

// errUnknownPropagator is returned when an unknown propagator name is used in
// the OTEL_PROPAGATORS environment variable.
var errUnknownPropagator = errors.New("unknown propagator")

// parseEnv returns the composite TextMapPropagators defined by the
// OTEL_PROPAGATORS environment variable. A nil TextMapPropagator is returned
// if no propagator is defined for the environment variable. A no-op
// TextMapPropagator will be returned if "none" is defined anywhere in the
// environment variable.
func parseEnv() (propagation.TextMapPropagator, error) {
propStrs, defined := os.LookupEnv(otelPropagatorsEnvKey)
if !defined {
return nil, nil
}

const sep = ","

var (
props []propagation.TextMapPropagator
unknown []string
)

for _, pStr := range strings.Split(propStrs, sep) {
if pStr == none {
// If "none" is passed in combination with any other propagator,
// the result still needs to be a no-op propagator. Therefore,
// short-circuit here.
return propagation.NewCompositeTextMapPropagator(), nil
}

p, ok := envRegistry.load(pStr)
if !ok {
unknown = append(unknown, pStr)
continue
}
props = append(props, p)
}

var err error
if len(unknown) > 0 {
joined := strings.Join(unknown, sep)
err = fmt.Errorf("%w: %s", errUnknownPropagator, joined)
}

switch len(props) {
case 0:
return nil, err
case 1:
// Do not return a composite of a single propagator.
return props[0], err
default:
return propagation.NewCompositeTextMapPropagator(props...), err
}
}