Skip to content

Commit cb2b04a

Browse files
committed
Add support for deprecated component type aliases
This change allows component authors to register one optional deprecated alias per component type, enabling smooth migrations when renaming components. When an alias is used in configuration, the collector will automatically resolve it to the original component and log a deprecation warning. Changes: - Add `WithDeprecatedTypeAlias` factory option to experimental modules (xreceiver, xexporter, xprocessor, xconnector) - Add `DeprecatedAlias()` method to factory interfaces - Generate alias expansion code in builder template that: - Populates factory maps with aliases pointing to original factories - Updates module information maps for aliased types - Validates that aliases don't conflict with existing component types - Add deprecation warnings that log when an alias is used: "Using deprecated alias <alias>; use <original> instead" Extensions are left aside for now.
1 parent a331a4c commit cb2b04a

File tree

16 files changed

+261
-0
lines changed

16 files changed

+261
-0
lines changed

.chloggen/type-aliases.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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. receiver/otlp)
7+
component: all
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add support for deprecated component type aliases
11+
12+
# One or more tracking issues or pull requests related to the change
13+
issues: [14208]
14+
15+
# Optional: The change log or logs in which this entry should be included.
16+
# e.g. '[user]' or '[user, api]'
17+
# Include 'user' if the change is relevant to end users.
18+
# Include 'api' if there is a change to a library API.
19+
# Default: '[user]'
20+
change_logs: [api]

cmd/builder/internal/builder/templates/components.go.tmpl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
package main
44

55
import (
6+
"fmt"
7+
68
"go.opentelemetry.io/collector/component"
79
"go.opentelemetry.io/collector/connector"
810
"go.opentelemetry.io/collector/exporter"
@@ -28,6 +30,24 @@ import (
2830
{{- end}}
2931
)
3032

33+
type aliasProvider interface{ DeprecatedAlias() component.Type }
34+
35+
func expandWithAliases[T component.Factory](factories map[component.Type]T, modules map[component.Type]string, componentKind string) error {
36+
for compType, factory := range factories {
37+
if ap, ok := any(factory).(aliasProvider); ok {
38+
alias := ap.DeprecatedAlias()
39+
if alias.String() != "" {
40+
if _, exists := factories[alias]; exists {
41+
return fmt.Errorf("deprecated %s alias %q conflicts with existing factory", componentKind, alias)
42+
}
43+
factories[alias] = factory
44+
modules[alias] = modules[compType]
45+
}
46+
}
47+
}
48+
return nil
49+
}
50+
3151
func components() (otelcol.Factories, error) {
3252
var err error
3353
factories := otelcol.Factories{
@@ -59,6 +79,9 @@ func components() (otelcol.Factories, error) {
5979
{{- range .Receivers}}
6080
factories.ReceiverModules[{{.Name}}.NewFactory().Type()] = "{{.GoMod}}"
6181
{{- end}}
82+
if err = expandWithAliases(factories.Receivers, factories.ReceiverModules, "receiver"); err != nil {
83+
return otelcol.Factories{}, err
84+
}
6285

6386
factories.Exporters, err = otelcol.MakeFactoryMap[exporter.Factory](
6487
{{- range .Exporters}}
@@ -72,6 +95,9 @@ func components() (otelcol.Factories, error) {
7295
{{- range .Exporters}}
7396
factories.ExporterModules[{{.Name}}.NewFactory().Type()] = "{{.GoMod}}"
7497
{{- end}}
98+
if err = expandWithAliases(factories.Exporters, factories.ExporterModules, "exporter"); err != nil {
99+
return otelcol.Factories{}, err
100+
}
75101

76102
factories.Processors, err = otelcol.MakeFactoryMap[processor.Factory](
77103
{{- range .Processors}}
@@ -85,6 +111,9 @@ func components() (otelcol.Factories, error) {
85111
{{- range .Processors}}
86112
factories.ProcessorModules[{{.Name}}.NewFactory().Type()] = "{{.GoMod}}"
87113
{{- end}}
114+
if err = expandWithAliases(factories.Processors, factories.ProcessorModules, "processor"); err != nil {
115+
return otelcol.Factories{}, err
116+
}
88117

89118
factories.Connectors, err = otelcol.MakeFactoryMap[connector.Factory](
90119
{{- range .Connectors}}
@@ -98,6 +127,9 @@ func components() (otelcol.Factories, error) {
98127
{{- range .Connectors}}
99128
factories.ConnectorModules[{{.Name}}.NewFactory().Type()] = "{{.GoMod}}"
100129
{{- end}}
130+
if err = expandWithAliases(factories.Connectors, factories.ConnectorModules, "connector"); err != nil {
131+
return otelcol.Factories{}, err
132+
}
101133

102134
return factories, nil
103135
}

cmd/otelcorecol/components.go

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

connector/xconnector/connector.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,14 @@ func WithProfilesToLogs(createProfilesToLogs CreateProfilesToLogsFunc, sl compon
213213
})
214214
}
215215

216+
// WithDeprecatedTypeAlias configures a deprecated type alias for the connector. Only one alias is supported per connector.
217+
// When the alias is used in configuration, a deprecation warning is automatically logged.
218+
func WithDeprecatedTypeAlias(alias component.Type) FactoryOption {
219+
return factoryOptionFunc(func(o *factoryOpts) {
220+
o.deprecatedAlias = alias
221+
})
222+
}
223+
216224
// factory implements the Factory interface.
217225
type factory struct {
218226
connector.Factory
@@ -234,6 +242,11 @@ type factory struct {
234242
profilesToTracesStabilityLevel component.StabilityLevel
235243
profilesToMetricsStabilityLevel component.StabilityLevel
236244
profilesToLogsStabilityLevel component.StabilityLevel
245+
deprecatedAlias component.Type
246+
}
247+
248+
func (f *factory) DeprecatedAlias() component.Type {
249+
return f.deprecatedAlias
237250
}
238251

239252
func (f *factory) TracesToProfilesStability() component.StabilityLevel {

connector/xconnector/connector_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,23 @@ func createProfilesToMetrics(context.Context, connector.Settings, component.Conf
146146
func createProfilesToLogs(context.Context, connector.Settings, component.Config, consumer.Logs) (Profiles, error) {
147147
return nopInstance, nil
148148
}
149+
150+
func TestNewFactoryWithDeprecatedAlias(t *testing.T) {
151+
testType := component.MustNewType("newname")
152+
aliasType := component.MustNewType("oldname")
153+
defaultCfg := struct{}{}
154+
155+
factory := NewFactory(
156+
testType,
157+
func() component.Config { return &defaultCfg },
158+
WithProfilesToProfiles(createProfilesToProfiles, component.StabilityLevelAlpha),
159+
WithDeprecatedTypeAlias(aliasType),
160+
)
161+
162+
assert.Equal(t, testType, factory.Type())
163+
assert.Equal(t, aliasType, factory.DeprecatedAlias())
164+
assert.EqualValues(t, &defaultCfg, factory.CreateDefaultConfig())
165+
166+
_, err := factory.CreateProfilesToProfiles(context.Background(), connector.Settings{ID: component.MustNewIDWithName("type", "name")}, &defaultCfg, consumertest.NewNop())
167+
require.NoError(t, err)
168+
}

exporter/xexporter/exporter.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,29 @@ func WithProfiles(createProfiles CreateProfilesFunc, sl component.StabilityLevel
8181
})
8282
}
8383

84+
// WithDeprecatedTypeAlias configures a deprecated type alias for the exporter. Only one alias is supported per exporter.
85+
// When the alias is used in configuration, a deprecation warning is automatically logged.
86+
func WithDeprecatedTypeAlias(alias component.Type) FactoryOption {
87+
return factoryOptionFunc(func(o *factoryOpts) {
88+
o.deprecatedAlias = alias
89+
})
90+
}
91+
8492
type factory struct {
8593
exporter.Factory
8694
createProfilesFunc CreateProfilesFunc
8795
profilesStabilityLevel component.StabilityLevel
96+
deprecatedAlias component.Type
8897
}
8998

9099
func (f *factory) ProfilesStability() component.StabilityLevel {
91100
return f.profilesStabilityLevel
92101
}
93102

103+
func (f *factory) DeprecatedAlias() component.Type {
104+
return f.deprecatedAlias
105+
}
106+
94107
func (f *factory) CreateProfiles(ctx context.Context, set exporter.Settings, cfg component.Config) (Profiles, error) {
95108
if f.createProfilesFunc == nil {
96109
return nil, pipeline.ErrSignalNotSupported

exporter/xexporter/exporter_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,23 @@ type nop struct {
5353
func createProfiles(context.Context, exporter.Settings, component.Config) (Profiles, error) {
5454
return nopInstance, nil
5555
}
56+
57+
func TestNewFactoryWithDeprecatedAlias(t *testing.T) {
58+
testType := component.MustNewType("newname")
59+
aliasType := component.MustNewType("oldname")
60+
defaultCfg := struct{}{}
61+
62+
factory := NewFactory(
63+
testType,
64+
func() component.Config { return &defaultCfg },
65+
WithProfiles(createProfiles, component.StabilityLevelAlpha),
66+
WithDeprecatedTypeAlias(aliasType),
67+
)
68+
69+
assert.Equal(t, testType, factory.Type())
70+
assert.Equal(t, aliasType, factory.DeprecatedAlias())
71+
assert.EqualValues(t, &defaultCfg, factory.CreateDefaultConfig())
72+
73+
_, err := factory.CreateProfiles(context.Background(), exporter.Settings{ID: component.MustNewID("newname")}, &defaultCfg)
74+
require.NoError(t, err)
75+
}

processor/xprocessor/processor.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,17 @@ type factory struct {
5656
processor.Factory
5757
createProfilesFunc CreateProfilesFunc
5858
profilesStabilityLevel component.StabilityLevel
59+
deprecatedAlias component.Type
5960
}
6061

6162
func (f factory) ProfilesStability() component.StabilityLevel {
6263
return f.profilesStabilityLevel
6364
}
6465

66+
func (f factory) DeprecatedAlias() component.Type {
67+
return f.deprecatedAlias
68+
}
69+
6570
func (f factory) CreateProfiles(ctx context.Context, set processor.Settings, cfg component.Config, next xconsumer.Profiles) (Profiles, error) {
6671
if f.createProfilesFunc == nil {
6772
return nil, pipeline.ErrSignalNotSupported
@@ -106,6 +111,14 @@ func WithProfiles(createProfiles CreateProfilesFunc, sl component.StabilityLevel
106111
})
107112
}
108113

114+
// WithDeprecatedTypeAlias configures a deprecated type alias for the processor. Only one alias is supported per processor.
115+
// When the alias is used in configuration, a deprecation warning is automatically logged.
116+
func WithDeprecatedTypeAlias(alias component.Type) FactoryOption {
117+
return factoryOptionFunc(func(o *factoryOpts) {
118+
o.deprecatedAlias = alias
119+
})
120+
}
121+
109122
// NewFactory returns a Factory.
110123
func NewFactory(cfgType component.Type, createDefaultConfig component.CreateDefaultConfigFunc, options ...FactoryOption) Factory {
111124
opts := factoryOpts{factory: &factory{}}

processor/xprocessor/processor_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,23 @@ type nopProcessor struct {
5454
func createProfiles(context.Context, processor.Settings, component.Config, xconsumer.Profiles) (Profiles, error) {
5555
return nopInstance, nil
5656
}
57+
58+
func TestNewFactoryWithDeprecatedAlias(t *testing.T) {
59+
testType := component.MustNewType("newname")
60+
aliasType := component.MustNewType("oldname")
61+
defaultCfg := struct{}{}
62+
63+
factory := NewFactory(
64+
testType,
65+
func() component.Config { return &defaultCfg },
66+
WithProfiles(createProfiles, component.StabilityLevelAlpha),
67+
WithDeprecatedTypeAlias(aliasType),
68+
)
69+
70+
assert.Equal(t, testType, factory.Type())
71+
assert.Equal(t, aliasType, factory.DeprecatedAlias())
72+
assert.EqualValues(t, &defaultCfg, factory.CreateDefaultConfig())
73+
74+
_, err := factory.CreateProfiles(context.Background(), processor.Settings{ID: component.MustNewID("newname")}, &defaultCfg, consumertest.NewNop())
75+
require.NoError(t, err)
76+
}

receiver/xreceiver/profiles.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,17 @@ type factory struct {
5858
receiver.Factory
5959
createProfilesFunc CreateProfilesFunc
6060
profilesStabilityLevel component.StabilityLevel
61+
deprecatedAlias component.Type
6162
}
6263

6364
func (f *factory) ProfilesStability() component.StabilityLevel {
6465
return f.profilesStabilityLevel
6566
}
6667

68+
func (f *factory) DeprecatedAlias() component.Type {
69+
return f.deprecatedAlias
70+
}
71+
6772
func (f *factory) CreateProfiles(ctx context.Context, set receiver.Settings, cfg component.Config, next xconsumer.Profiles) (Profiles, error) {
6873
if f.createProfilesFunc == nil {
6974
return nil, pipeline.ErrSignalNotSupported
@@ -108,6 +113,14 @@ func WithProfiles(createProfiles CreateProfilesFunc, sl component.StabilityLevel
108113
})
109114
}
110115

116+
// WithDeprecatedTypeAlias configures a deprecated type alias for the receiver. Only one alias is supported per receiver.
117+
// When the alias is used in configuration, a deprecation warning is automatically logged.
118+
func WithDeprecatedTypeAlias(alias component.Type) FactoryOption {
119+
return factoryOptionFunc(func(o *factoryOpts) {
120+
o.deprecatedAlias = alias
121+
})
122+
}
123+
111124
// NewFactory returns a Factory.
112125
func NewFactory(cfgType component.Type, createDefaultConfig component.CreateDefaultConfigFunc, options ...FactoryOption) Factory {
113126
opts := factoryOpts{factory: &factory{}}

0 commit comments

Comments
 (0)