Skip to content

Commit 25669b3

Browse files
dmathieudjaglowski
authored andcommitted
Hide profiles behind a feature gate (open-telemetry#11477)
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description This hides profiles support behind a feature gate, so folks have to enable them explicitly to be able to use them.
1 parent ddce501 commit 25669b3

File tree

3 files changed

+91
-13
lines changed

3 files changed

+91
-13
lines changed

.chloggen/profiles-featuregate.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
7+
component: service
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Hide profiles support behind a feature gate while it remains alpha.
11+
12+
# One or more tracking issues or pull requests related to the change
13+
issues: [11477]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# Optional: The change log or logs in which this entry should be included.
21+
# e.g. '[user]' or '[user, api]'
22+
# Include 'user' if the change is relevant to end users.
23+
# Include 'api' if there is a change to a library API.
24+
# Default: '[user]'
25+
change_logs: [user]

service/pipelines/config.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"fmt"
99

1010
"go.opentelemetry.io/collector/component"
11+
"go.opentelemetry.io/collector/featuregate"
1112
"go.opentelemetry.io/collector/pipeline"
1213
"go.opentelemetry.io/collector/pipeline/pipelineprofiles"
1314
)
@@ -16,6 +17,14 @@ var (
1617
errMissingServicePipelines = errors.New("service must have at least one pipeline")
1718
errMissingServicePipelineReceivers = errors.New("must have at least one receiver")
1819
errMissingServicePipelineExporters = errors.New("must have at least one exporter")
20+
21+
serviceProfileSupportGateID = "service.profilesSupport"
22+
serviceProfileSupportGate = featuregate.GlobalRegistry().MustRegister(
23+
serviceProfileSupportGateID,
24+
featuregate.StageAlpha,
25+
featuregate.WithRegisterFromVersion("v0.112.0"),
26+
featuregate.WithRegisterDescription("Controls whether profiles support can be enabled"),
27+
)
1928
)
2029

2130
// Config defines the configurable settings for service telemetry.
@@ -31,8 +40,16 @@ func (cfg Config) Validate() error {
3140
// only configured components.
3241
for pipelineID, p := range cfg {
3342
switch pipelineID.Signal() {
34-
case pipeline.SignalTraces, pipeline.SignalMetrics, pipeline.SignalLogs, pipelineprofiles.SignalProfiles:
43+
case pipeline.SignalTraces, pipeline.SignalMetrics, pipeline.SignalLogs:
3544
// Continue
45+
case pipelineprofiles.SignalProfiles:
46+
if !serviceProfileSupportGate.IsEnabled() {
47+
return fmt.Errorf(
48+
"pipeline %q: profiling signal support is at alpha level, gated under the %q feature gate",
49+
pipelineID.String(),
50+
serviceProfileSupportGateID,
51+
)
52+
}
3653
default:
3754
return fmt.Errorf("pipeline %q: unknown signal %q", pipelineID.String(), pipelineID.Signal())
3855
}

service/pipelines/config_test.go

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,18 @@ import (
99
"testing"
1010

1111
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
1213

1314
"go.opentelemetry.io/collector/component"
15+
"go.opentelemetry.io/collector/featuregate"
1416
"go.opentelemetry.io/collector/pipeline"
17+
"go.opentelemetry.io/collector/pipeline/pipelineprofiles"
1518
)
1619

1720
func TestConfigValidate(t *testing.T) {
1821
var testCases = []struct {
1922
name string // test case name (also file name containing config yaml)
20-
cfgFn func() Config
23+
cfgFn func(*testing.T) Config
2124
expected error
2225
}{
2326
{
@@ -27,8 +30,8 @@ func TestConfigValidate(t *testing.T) {
2730
},
2831
{
2932
name: "duplicate-processor-reference",
30-
cfgFn: func() Config {
31-
cfg := generateConfig()
33+
cfgFn: func(*testing.T) Config {
34+
cfg := generateConfig(t)
3235
pipe := cfg[pipeline.NewID(pipeline.SignalTraces)]
3336
pipe.Processors = append(pipe.Processors, pipe.Processors...)
3437
return cfg
@@ -37,33 +40,33 @@ func TestConfigValidate(t *testing.T) {
3740
},
3841
{
3942
name: "missing-pipeline-receivers",
40-
cfgFn: func() Config {
41-
cfg := generateConfig()
43+
cfgFn: func(*testing.T) Config {
44+
cfg := generateConfig(t)
4245
cfg[pipeline.NewID(pipeline.SignalTraces)].Receivers = nil
4346
return cfg
4447
},
4548
expected: fmt.Errorf(`pipeline "traces": %w`, errMissingServicePipelineReceivers),
4649
},
4750
{
4851
name: "missing-pipeline-exporters",
49-
cfgFn: func() Config {
50-
cfg := generateConfig()
52+
cfgFn: func(*testing.T) Config {
53+
cfg := generateConfig(t)
5154
cfg[pipeline.NewID(pipeline.SignalTraces)].Exporters = nil
5255
return cfg
5356
},
5457
expected: fmt.Errorf(`pipeline "traces": %w`, errMissingServicePipelineExporters),
5558
},
5659
{
5760
name: "missing-pipelines",
58-
cfgFn: func() Config {
61+
cfgFn: func(*testing.T) Config {
5962
return nil
6063
},
6164
expected: errMissingServicePipelines,
6265
},
6366
{
6467
name: "invalid-service-pipeline-type",
65-
cfgFn: func() Config {
66-
cfg := generateConfig()
68+
cfgFn: func(*testing.T) Config {
69+
cfg := generateConfig(t)
6770
cfg[pipeline.MustNewID("wrongtype")] = &PipelineConfig{
6871
Receivers: []component.ID{component.MustNewID("nop")},
6972
Processors: []component.ID{component.MustNewID("nop")},
@@ -73,17 +76,50 @@ func TestConfigValidate(t *testing.T) {
7376
},
7477
expected: errors.New(`pipeline "wrongtype": unknown signal "wrongtype"`),
7578
},
79+
{
80+
name: "disabled-featuregate-profiles",
81+
cfgFn: func(*testing.T) Config {
82+
cfg := generateConfig(t)
83+
cfg[pipeline.NewID(pipelineprofiles.SignalProfiles)] = &PipelineConfig{
84+
Receivers: []component.ID{component.MustNewID("nop")},
85+
Processors: []component.ID{component.MustNewID("nop")},
86+
Exporters: []component.ID{component.MustNewID("nop")},
87+
}
88+
return cfg
89+
},
90+
expected: errors.New(`pipeline "profiles": profiling signal support is at alpha level, gated under the "service.profilesSupport" feature gate`),
91+
},
92+
{
93+
name: "enabled-featuregate-profiles",
94+
cfgFn: func(t *testing.T) Config {
95+
require.NoError(t, featuregate.GlobalRegistry().Set(serviceProfileSupportGateID, true))
96+
97+
cfg := generateConfig(t)
98+
cfg[pipeline.NewID(pipelineprofiles.SignalProfiles)] = &PipelineConfig{
99+
Receivers: []component.ID{component.MustNewID("nop")},
100+
Processors: []component.ID{component.MustNewID("nop")},
101+
Exporters: []component.ID{component.MustNewID("nop")},
102+
}
103+
return cfg
104+
},
105+
expected: nil,
106+
},
76107
}
77108

78109
for _, tt := range testCases {
79110
t.Run(tt.name, func(t *testing.T) {
80-
cfg := tt.cfgFn()
111+
cfg := tt.cfgFn(t)
81112
assert.Equal(t, tt.expected, cfg.Validate())
113+
114+
// Clean up the profiles support gate, which may have been enabled in `cfgFn`.
115+
require.NoError(t, featuregate.GlobalRegistry().Set(serviceProfileSupportGateID, false))
82116
})
83117
}
84118
}
85119

86-
func generateConfig() Config {
120+
func generateConfig(t *testing.T) Config {
121+
t.Helper()
122+
87123
return map[pipeline.ID]*PipelineConfig{
88124
pipeline.NewID(pipeline.SignalTraces): {
89125
Receivers: []component.ID{component.MustNewID("nop")},

0 commit comments

Comments
 (0)