From 904cb53b3c5de8396d220579ad0c25c85275be9e Mon Sep 17 00:00:00 2001 From: Evan Bradley <11745660+evan-bradley@users.noreply.github.com> Date: Wed, 11 Feb 2026 16:46:24 -0500 Subject: [PATCH 1/3] [cmd/builder] Allow configuring telemetry providers --- .chloggen/builder-telemetry-factories.yaml | 27 +++++++++++++++++ cmd/builder/README.md | 9 ++++-- cmd/builder/internal/builder/config.go | 29 ++++++++++++++++++- cmd/builder/internal/builder/config_test.go | 22 ++++++++++---- .../builder/templates/components.go.tmpl | 4 +-- .../internal/builder/templates/go.mod.tmpl | 2 ++ cmd/builder/internal/config/default.yaml | 4 +++ cmd/otelcorecol/builder-config.yaml | 4 +++ 8 files changed, 90 insertions(+), 11 deletions(-) create mode 100644 .chloggen/builder-telemetry-factories.yaml diff --git a/.chloggen/builder-telemetry-factories.yaml b/.chloggen/builder-telemetry-factories.yaml new file mode 100644 index 00000000000..2abf065e536 --- /dev/null +++ b/.chloggen/builder-telemetry-factories.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. receiver/otlp) +component: cmd/builder + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add "telemetry" field to allow configuring telemetry providers + +# One or more tracking issues or pull requests related to the change +issues: [] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: | + Most users should not need to use this, this field should only be set if you + intend to provide your own OpenTelemetry SDK. + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/cmd/builder/README.md b/cmd/builder/README.md index f91e2d54642..55279bf5e03 100644 --- a/cmd/builder/README.md +++ b/cmd/builder/README.md @@ -141,7 +141,9 @@ The configuration file is composed of two main parts: `dist` and module types. A ocb --config=config.yaml ``` -The module types are specified at the top-level, and might be: `extensions`, `exporters`, `receivers` and `processors`. They all accept a list of components, and each component is required to have at least the `gomod` entry. When not specified, the `import` value is inferred from the `gomod`. When not specified, the `name` is inferred from the `import`. +The module types are specified at the top-level. Available options are `extensions`, `exporters`, `receivers`, `processors`, `providers`, and `converters`. They all accept a list of components, and each component is required to have at least the `gomod` entry. The telemetry provider for the Collector binary can also be specified through the `telemetry` key, which can be set to a single module, also requiring a `gomod` entry at a minimum. + +When not specified, the `import` value is inferred from the `gomod`. When not specified, the `name` is inferred from the `import`. The `import` might specify a more specific path than what is specified in the `gomod`. For instance, your Go module might be `gitlab.com/myorg/myrepo` and the `import` might be `gitlab.com/myorg/myrepo/myexporter`. @@ -159,10 +161,13 @@ dist: go: "/usr/bin/go" # which Go binary to use to compile the generated sources. Optional. debug_compilation: false # enabling this causes the builder to keep the debug symbols in the resulting binary. Optional. exporters: - - gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/alibabacloudlogserviceexporter v0.129.0" # the Go module for the component. Required. + - gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/alibabacloudlogserviceexporter v0.146.0" # the Go module for the component. Required. import: "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/alibabacloudlogserviceexporter" # the import path for the component. Optional. name: "alibabacloudlogserviceexporter" # package name to use in the generated sources. Optional. path: "./alibabacloudlogserviceexporter" # in case a local version should be used for the module, the path relative to the current dir, or a full path can be specified. Optional. +telemetry: + gomod: go.opentelemetry.io/collector/service v0.146.0 + import: go.opentelemetry.io/collector/service/telemetry/otelconftelemetry replaces: # a list of "replaces" directives that will be part of the resulting go.mod - github.com/open-telemetry/opentelemetry-collector-contrib/internal/common => github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.128.0 diff --git a/cmd/builder/internal/builder/config.go b/cmd/builder/internal/builder/config.go index b6677418393..5c11c2f178a 100644 --- a/cmd/builder/internal/builder/config.go +++ b/cmd/builder/internal/builder/config.go @@ -46,6 +46,7 @@ type Config struct { Receivers []Module `mapstructure:"receivers"` Processors []Module `mapstructure:"processors"` Connectors []Module `mapstructure:"connectors"` + Telemetry *Module `mapstructure:"telemetry"` ConfmapProviders []Module `mapstructure:"providers"` ConfmapConverters []Module `mapstructure:"converters"` Replaces []string `mapstructure:"replaces"` @@ -144,6 +145,7 @@ func (c *Config) Validate() error { validateModules("connector", c.Connectors), validateModules("provider", c.ConfmapProviders), validateModules("converter", c.ConfmapConverters), + validateTelemetry(c), ) } @@ -193,6 +195,12 @@ func (c *Config) ParseModules() error { return err } + telemetry, err := parseModules([]Module{*c.Telemetry}, usedNames) + if err != nil { + return err + } + c.Telemetry = &telemetry[0] + c.ConfmapProviders, err = parseModules(c.ConfmapProviders, usedNames) if err != nil { return err @@ -205,7 +213,7 @@ func (c *Config) ParseModules() error { } func (c *Config) allComponents() []Module { - return slices.Concat[[]Module](c.Exporters, c.Receivers, c.Processors, c.Extensions, c.Connectors, c.ConfmapProviders, c.ConfmapConverters) + return slices.Concat(c.Exporters, c.Receivers, c.Processors, c.Extensions, c.Connectors, []Module{*c.Telemetry}, c.ConfmapProviders, c.ConfmapConverters) } func validateModules(name string, mods []Module) error { @@ -217,6 +225,25 @@ func validateModules(name string, mods []Module) error { return nil } +// validateTelemetry ensures there is a valid telemetry module specified. +// If the field is not set, it is defaulted to otelconftelemetry. +func validateTelemetry(c *Config) error { + // We cannot set this in createDefaultConfig, since koanf merges maps and we + // would get a blend of this value and user-provided values. Once + // otelconftelemetry is its own module (that is, the `Import` field is not + // set), we can likely move the default to createDefaultConfig. + if c.Telemetry == nil { + c.Telemetry = &Module{ + GoMod: "go.opentelemetry.io/collector/service " + DefaultBetaOtelColVersion, + Import: "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry", + } + } else if c.Telemetry.GoMod == "" { + return fmt.Errorf("telemetry module: %w", errMissingGoMod) + } + + return nil +} + func parseModules(mods []Module, usedNames map[string]int) ([]Module, error) { var parsedModules []Module for _, mod := range mods { diff --git a/cmd/builder/internal/builder/config_test.go b/cmd/builder/internal/builder/config_test.go index 14ca9bbe552..2c5a81fd0b7 100644 --- a/cmd/builder/internal/builder/config_test.go +++ b/cmd/builder/internal/builder/config_test.go @@ -275,6 +275,15 @@ func TestMissingModule(t *testing.T) { }, err: errMissingGoMod, }, + { + cfg: Config{ + Logger: zap.NewNop(), + Telemetry: &Module{ + Import: "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry", + }, + }, + err: errMissingGoMod, + }, } for _, test := range configurations { @@ -285,10 +294,11 @@ func TestMissingModule(t *testing.T) { func TestNewDefaultConfig(t *testing.T) { cfg, err := NewDefaultConfig() require.NoError(t, err) - require.NoError(t, cfg.ParseModules()) - assert.NoError(t, cfg.Validate()) - assert.NoError(t, cfg.SetGoPath()) + assert.Nil(t, cfg.Telemetry) require.NoError(t, cfg.Validate()) + require.NoError(t, cfg.SetGoPath()) + require.NoError(t, cfg.ParseModules()) + assert.NotNil(t, cfg.Telemetry) assert.False(t, cfg.Distribution.DebugCompilation) assert.Empty(t, cfg.Distribution.BuildTags) assert.False(t, cfg.LDSet) @@ -305,9 +315,9 @@ func TestNewBuiltinConfig(t *testing.T) { cfg := Config{Logger: zaptest.NewLogger(t)} require.NoError(t, k.UnmarshalWithConf("", &cfg, koanf.UnmarshalConf{Tag: "mapstructure"})) - assert.NoError(t, cfg.ParseModules()) - assert.NoError(t, cfg.Validate()) - assert.NoError(t, cfg.SetGoPath()) + require.NoError(t, cfg.Validate()) + require.NoError(t, cfg.SetGoPath()) + require.NoError(t, cfg.ParseModules()) // Unlike the config initialized in NewDefaultConfig(), we expect // the builtin default to be practically useful, so there must be diff --git a/cmd/builder/internal/builder/templates/components.go.tmpl b/cmd/builder/internal/builder/templates/components.go.tmpl index 4fe7dfc81f8..0348d8e5e29 100644 --- a/cmd/builder/internal/builder/templates/components.go.tmpl +++ b/cmd/builder/internal/builder/templates/components.go.tmpl @@ -10,7 +10,7 @@ import ( "go.opentelemetry.io/collector/otelcol" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/receiver" - "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" + {{.Telemetry.Name}} "{{.Telemetry.Import}}" {{- range .Connectors}} {{.Name}} "{{.Import}}" {{- end}} @@ -45,7 +45,7 @@ func makeModulesMap[T component.Factory](factories map[component.Type]T, modules func components() (otelcol.Factories, error) { var err error factories := otelcol.Factories{ - Telemetry: otelconftelemetry.NewFactory(), + Telemetry: {{.Telemetry.Name}}.NewFactory(), } factories.Extensions, err = otelcol.MakeFactoryMap[extension.Factory]( diff --git a/cmd/builder/internal/builder/templates/go.mod.tmpl b/cmd/builder/internal/builder/templates/go.mod.tmpl index 13ce9852a9a..939c59bfec7 100644 --- a/cmd/builder/internal/builder/templates/go.mod.tmpl +++ b/cmd/builder/internal/builder/templates/go.mod.tmpl @@ -26,6 +26,7 @@ require ( {{- range .Processors}} {{if .GoMod}}{{.GoMod}}{{end}} {{- end}} + {{if .Telemetry.GoMod}}{{.Telemetry.GoMod}}{{end}} go.opentelemetry.io/collector/otelcol {{.OtelColVersion}} ) @@ -55,6 +56,7 @@ require ( {{- range .Processors}} {{if ne .Path ""}}replace {{.GoMod}} => {{.Path}}{{end}} {{- end}} +{{if ne .Telemetry.Path ""}}replace {{.Telemetry.GoMod}} => {{.Telemetry.Path}}{{end}} {{- range .Replaces}} replace {{.}} {{- end}} diff --git a/cmd/builder/internal/config/default.yaml b/cmd/builder/internal/config/default.yaml index 4e69b9b8c83..9d8a366efc7 100644 --- a/cmd/builder/internal/config/default.yaml +++ b/cmd/builder/internal/config/default.yaml @@ -36,3 +36,7 @@ providers: - gomod: go.opentelemetry.io/collector/confmap/provider/httpsprovider v1.51.0 - gomod: go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.51.0 +telemetry: + gomod: go.opentelemetry.io/collector/service v0.145.0 + import: go.opentelemetry.io/collector/service/telemetry/otelconftelemetry + diff --git a/cmd/otelcorecol/builder-config.yaml b/cmd/otelcorecol/builder-config.yaml index 2cb8e1f5d36..986e17f01fc 100644 --- a/cmd/otelcorecol/builder-config.yaml +++ b/cmd/otelcorecol/builder-config.yaml @@ -36,6 +36,10 @@ providers: - gomod: go.opentelemetry.io/collector/confmap/provider/httpsprovider v1.51.0 - gomod: go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.51.0 +telemetry: + gomod: go.opentelemetry.io/collector/service v0.145.0 + import: go.opentelemetry.io/collector/service/telemetry/otelconftelemetry + replaces: - go.opentelemetry.io/collector => ../../ - go.opentelemetry.io/collector/client => ../../client From b5f12c3b64f319ac81eb701ea972a06cd09fa5b2 Mon Sep 17 00:00:00 2001 From: Evan Bradley <11745660+evan-bradley@users.noreply.github.com> Date: Wed, 11 Feb 2026 17:10:14 -0500 Subject: [PATCH 2/3] Fix build errors --- cmd/builder/internal/builder/config.go | 12 ++++++------ cmd/builder/internal/builder/config_test.go | 13 ++++++++++--- cmd/otelcorecol/components.go | 2 +- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/cmd/builder/internal/builder/config.go b/cmd/builder/internal/builder/config.go index 5c11c2f178a..4b49e657d3a 100644 --- a/cmd/builder/internal/builder/config.go +++ b/cmd/builder/internal/builder/config.go @@ -46,7 +46,7 @@ type Config struct { Receivers []Module `mapstructure:"receivers"` Processors []Module `mapstructure:"processors"` Connectors []Module `mapstructure:"connectors"` - Telemetry *Module `mapstructure:"telemetry"` + Telemetry Module `mapstructure:"telemetry"` ConfmapProviders []Module `mapstructure:"providers"` ConfmapConverters []Module `mapstructure:"converters"` Replaces []string `mapstructure:"replaces"` @@ -195,11 +195,11 @@ func (c *Config) ParseModules() error { return err } - telemetry, err := parseModules([]Module{*c.Telemetry}, usedNames) + telemetry, err := parseModules([]Module{c.Telemetry}, usedNames) if err != nil { return err } - c.Telemetry = &telemetry[0] + c.Telemetry = telemetry[0] c.ConfmapProviders, err = parseModules(c.ConfmapProviders, usedNames) if err != nil { @@ -213,7 +213,7 @@ func (c *Config) ParseModules() error { } func (c *Config) allComponents() []Module { - return slices.Concat(c.Exporters, c.Receivers, c.Processors, c.Extensions, c.Connectors, []Module{*c.Telemetry}, c.ConfmapProviders, c.ConfmapConverters) + return slices.Concat(c.Exporters, c.Receivers, c.Processors, c.Extensions, c.Connectors, []Module{c.Telemetry}, c.ConfmapProviders, c.ConfmapConverters) } func validateModules(name string, mods []Module) error { @@ -232,8 +232,8 @@ func validateTelemetry(c *Config) error { // would get a blend of this value and user-provided values. Once // otelconftelemetry is its own module (that is, the `Import` field is not // set), we can likely move the default to createDefaultConfig. - if c.Telemetry == nil { - c.Telemetry = &Module{ + if c.Telemetry.Name == "" && c.Telemetry.Import == "" && c.Telemetry.GoMod == "" && c.Telemetry.Path == "" { + c.Telemetry = Module{ GoMod: "go.opentelemetry.io/collector/service " + DefaultBetaOtelColVersion, Import: "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry", } diff --git a/cmd/builder/internal/builder/config_test.go b/cmd/builder/internal/builder/config_test.go index 2c5a81fd0b7..116ae9f102d 100644 --- a/cmd/builder/internal/builder/config_test.go +++ b/cmd/builder/internal/builder/config_test.go @@ -70,6 +70,9 @@ func TestAliases(t *testing.T) { GoMod: "github.com/another3/module v0.1.2", }, }, + Telemetry: Module{ + GoMod: "github.com/another3/module v0.1.2", + }, } // test @@ -128,6 +131,10 @@ func TestAliases(t *testing.T) { assert.Equal(t, "github.com/another3/module v0.1.2", cfg.Connectors[2].GoMod) assert.Equal(t, "github.com/another3/module", cfg.Connectors[2].Import) assert.Equal(t, "module5", cfg.Connectors[2].Name) + + assert.Equal(t, "github.com/another3/module v0.1.2", cfg.Telemetry.GoMod) + assert.Equal(t, "github.com/another3/module", cfg.Telemetry.Import) + assert.Equal(t, "module6", cfg.Telemetry.Name) } func TestParseModules(t *testing.T) { @@ -278,7 +285,7 @@ func TestMissingModule(t *testing.T) { { cfg: Config{ Logger: zap.NewNop(), - Telemetry: &Module{ + Telemetry: Module{ Import: "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry", }, }, @@ -294,11 +301,11 @@ func TestMissingModule(t *testing.T) { func TestNewDefaultConfig(t *testing.T) { cfg, err := NewDefaultConfig() require.NoError(t, err) - assert.Nil(t, cfg.Telemetry) + assert.Empty(t, cfg.Telemetry.GoMod) require.NoError(t, cfg.Validate()) require.NoError(t, cfg.SetGoPath()) require.NoError(t, cfg.ParseModules()) - assert.NotNil(t, cfg.Telemetry) + assert.NotEmpty(t, cfg.Telemetry.GoMod) assert.False(t, cfg.Distribution.DebugCompilation) assert.Empty(t, cfg.Distribution.BuildTags) assert.False(t, cfg.LDSet) diff --git a/cmd/otelcorecol/components.go b/cmd/otelcorecol/components.go index b08230653d0..144f21b3073 100644 --- a/cmd/otelcorecol/components.go +++ b/cmd/otelcorecol/components.go @@ -21,7 +21,7 @@ import ( "go.opentelemetry.io/collector/receiver" nopreceiver "go.opentelemetry.io/collector/receiver/nopreceiver" otlpreceiver "go.opentelemetry.io/collector/receiver/otlpreceiver" - "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" + otelconftelemetry "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" ) type aliasProvider interface{ DeprecatedAlias() component.Type } From 6ffe955a61c67de314259fc260f1126943ff4cda Mon Sep 17 00:00:00 2001 From: Pablo Baeyens Date: Thu, 12 Feb 2026 10:24:46 +0100 Subject: [PATCH 3/3] Update .chloggen/builder-telemetry-factories.yaml --- .chloggen/builder-telemetry-factories.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.chloggen/builder-telemetry-factories.yaml b/.chloggen/builder-telemetry-factories.yaml index 2abf065e536..21789c5f4c8 100644 --- a/.chloggen/builder-telemetry-factories.yaml +++ b/.chloggen/builder-telemetry-factories.yaml @@ -10,7 +10,7 @@ component: cmd/builder note: Add "telemetry" field to allow configuring telemetry providers # One or more tracking issues or pull requests related to the change -issues: [] +issues: [14575] # (Optional) One or more lines of additional information to render under the primary note. # These lines will be padded with 2 spaces and then inserted directly into the document.