Skip to content

Commit 7e4006a

Browse files
flc1125dmathieu
andauthored
chore: generate feature flag files from shared (#7361)
Given the observed facts, multiple components need to depend on the x package together. To reduce duplication and unify style management, this PR is added. PS: Currently only `go.opentelemetry.io/otel/exporters/stdout/stdouttrace` is supported; other components will be supplemented after this PR is merged. --------- Co-authored-by: Damien Mathieu <[email protected]>
1 parent 5b808c6 commit 7e4006a

File tree

7 files changed

+209
-27
lines changed

7 files changed

+209
-27
lines changed

exporters/stdout/stdouttrace/internal/gen.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ package internal // import "go.opentelemetry.io/otel/exporters/stdout/stdouttrac
77

88
//go:generate gotmpl --body=../../../../internal/shared/counter/counter.go.tmpl "--data={ \"pkg\": \"go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/counter\" }" --out=counter/counter.go
99
//go:generate gotmpl --body=../../../../internal/shared/counter/counter_test.go.tmpl "--data={}" --out=counter/counter_test.go
10+
11+
//go:generate gotmpl --body=../../../../internal/shared/x/x.go.tmpl "--data={ \"pkg\": \"go.opentelemetry.io/otel/exporters/stdout/stdouttrace\" }" --out=x/x.go
12+
//go:generate gotmpl --body=../../../../internal/shared/x/x_test.go.tmpl "--data={}" --out=x/x_test.go
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
// Package x documents experimental features for [go.opentelemetry.io/otel/exporters/stdout/stdouttrace].
5+
package x // import "go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x"
6+
7+
import "strings"
8+
9+
// Observability is an experimental feature flag that determines if exporter
10+
// observability metrics are enabled.
11+
//
12+
// To enable this feature set the OTEL_GO_X_OBSERVABILITY environment variable
13+
// to the case-insensitive string value of "true" (i.e. "True" and "TRUE"
14+
// will also enable this).
15+
var Observability = newFeature(
16+
[]string{"OBSERVABILITY", "SELF_OBSERVABILITY"},
17+
func(v string) (string, bool) {
18+
if strings.EqualFold(v, "true") {
19+
return v, true
20+
}
21+
return "", false
22+
},
23+
)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package x
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func TestObservability(t *testing.T) {
13+
const key = "OTEL_GO_X_OBSERVABILITY"
14+
require.Contains(t, Observability.Keys(), key)
15+
16+
const altKey = "OTEL_GO_X_SELF_OBSERVABILITY"
17+
require.Contains(t, Observability.Keys(), altKey)
18+
19+
t.Run("100", run(setenv(key, "100"), assertDisabled(Observability)))
20+
t.Run("true", run(setenv(key, "true"), assertEnabled(Observability, "true")))
21+
t.Run("True", run(setenv(key, "True"), assertEnabled(Observability, "True")))
22+
t.Run("false", run(setenv(key, "false"), assertDisabled(Observability)))
23+
t.Run("empty", run(assertDisabled(Observability)))
24+
}

exporters/stdout/stdouttrace/internal/x/x.go

Lines changed: 3 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

exporters/stdout/stdouttrace/internal/x/x_test.go

Lines changed: 23 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/shared/x/x.go.tmpl

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Code generated by gotmpl. DO NOT MODIFY.
2+
// source: internal/shared/x/x.go.tmpl
3+
4+
// Copyright The OpenTelemetry Authors
5+
// SPDX-License-Identifier: Apache-2.0
6+
7+
// Package x documents experimental features for [{{.pkg}}].
8+
package x // import "{{.pkg}}/internal/x"
9+
10+
import (
11+
"os"
12+
)
13+
14+
// Feature is an experimental feature control flag. It provides a uniform way
15+
// to interact with these feature flags and parse their values.
16+
type Feature[T any] struct {
17+
keys []string
18+
parse func(v string) (T, bool)
19+
}
20+
21+
func newFeature[T any](suffix []string, parse func(string) (T, bool)) Feature[T] {
22+
const envKeyRoot = "OTEL_GO_X_"
23+
keys := make([]string, 0, len(suffix))
24+
for _, s := range suffix {
25+
keys = append(keys, envKeyRoot+s)
26+
}
27+
return Feature[T]{
28+
keys: keys,
29+
parse: parse,
30+
}
31+
}
32+
33+
// Keys returns the environment variable keys that can be set to enable the
34+
// feature.
35+
func (f Feature[T]) Keys() []string { return f.keys }
36+
37+
// Lookup returns the user configured value for the feature and true if the
38+
// user has enabled the feature. Otherwise, if the feature is not enabled, a
39+
// zero-value and false are returned.
40+
func (f Feature[T]) Lookup() (v T, ok bool) {
41+
// https://github.com/open-telemetry/opentelemetry-specification/blob/62effed618589a0bec416a87e559c0a9d96289bb/specification/configuration/sdk-environment-variables.md#parsing-empty-value
42+
//
43+
// > The SDK MUST interpret an empty value of an environment variable the
44+
// > same way as when the variable is unset.
45+
for _, key := range f.keys {
46+
vRaw := os.Getenv(key)
47+
if vRaw != "" {
48+
return f.parse(vRaw)
49+
}
50+
}
51+
return v, ok
52+
}
53+
54+
// Enabled reports whether the feature is enabled.
55+
func (f Feature[T]) Enabled() bool {
56+
_, ok := f.Lookup()
57+
return ok
58+
}

internal/shared/x/x_test.go.tmpl

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Code generated by gotmpl. DO NOT MODIFY.
2+
// source: internal/shared/x/x_text.go.tmpl
3+
4+
// Copyright The OpenTelemetry Authors
5+
// SPDX-License-Identifier: Apache-2.0
6+
7+
package x
8+
9+
import (
10+
"strings"
11+
"testing"
12+
13+
"github.com/stretchr/testify/assert"
14+
"github.com/stretchr/testify/require"
15+
)
16+
17+
const (
18+
mockKey = "OTEL_GO_X_MOCK_FEATURE"
19+
mockKey2 = "OTEL_GO_X_MOCK_FEATURE2"
20+
)
21+
22+
var mockFeature = newFeature([]string{"MOCK_FEATURE", "MOCK_FEATURE2"}, func(v string) (string, bool) {
23+
if strings.EqualFold(v, "true") {
24+
return v, true
25+
}
26+
return "", false
27+
})
28+
29+
func TestFeature(t *testing.T) {
30+
require.Contains(t, mockFeature.Keys(), mockKey)
31+
require.Contains(t, mockFeature.Keys(), mockKey2)
32+
33+
t.Run("100", run(setenv(mockKey, "100"), assertDisabled(mockFeature)))
34+
t.Run("true", run(setenv(mockKey, "true"), assertEnabled(mockFeature, "true")))
35+
t.Run("True", run(setenv(mockKey, "True"), assertEnabled(mockFeature, "True")))
36+
t.Run("false", run(setenv(mockKey, "false"), assertDisabled(mockFeature)))
37+
t.Run("empty", run(assertDisabled(mockFeature)))
38+
}
39+
40+
func run(steps ...func(*testing.T)) func(*testing.T) {
41+
return func(t *testing.T) {
42+
t.Helper()
43+
for _, step := range steps {
44+
step(t)
45+
}
46+
}
47+
}
48+
49+
func setenv(k, v string) func(t *testing.T) { //nolint:unparam // This is a reusable test utility function.
50+
return func(t *testing.T) { t.Setenv(k, v) }
51+
}
52+
53+
func assertEnabled[T any](f Feature[T], want T) func(*testing.T) {
54+
return func(t *testing.T) {
55+
t.Helper()
56+
assert.True(t, f.Enabled(), "not enabled")
57+
58+
v, ok := f.Lookup()
59+
assert.True(t, ok, "Lookup state")
60+
assert.Equal(t, want, v, "Lookup value")
61+
}
62+
}
63+
64+
func assertDisabled[T any](f Feature[T]) func(*testing.T) {
65+
var zero T
66+
return func(t *testing.T) {
67+
t.Helper()
68+
69+
assert.False(t, f.Enabled(), "enabled")
70+
71+
v, ok := f.Lookup()
72+
assert.False(t, ok, "Lookup state")
73+
assert.Equal(t, zero, v, "Lookup value")
74+
}
75+
}

0 commit comments

Comments
 (0)