Problem
Elastic Agent's OTel translator currently handles Beat receiver feature flags inconsistently.
The translator special-cases agent.features.fqdn.enabled and writes it into the generated Beat receiver config as features.fqdn.enabled. Other feature flags under agent.features.* are not propagated to Beat receivers through the same path, so Beat receiver behavior can diverge from process-managed Beats and from the operator's Agent policy.
This means only fqdn currently gets first-class treatment in generated Beat receiver configs, while other Beat-supported feature flags such as:
agent.features.log_input_run_as_filestream.enabled
agent.features.aws_s3_v2.enabled
are excluded from the generated receiver features block unless they are manually present in raw Beat/receiver config.
Current behavior
The OTel translator evaluates the Agent FQDN flag once and injects only that flag into each Beat receiver config:
- FQDN value read from Agent feature state:
|
// Evaluate the FQDN feature flag once, so every component in this render sees a consistent |
|
// value even if the global flag changes (via a concurrent policy update) while we iterate. |
|
fqdnEnabled := features.FQDN() |
- Hard-coded Beat receiver
features.fqdn.enabled block:
|
// propagate the FQDN feature flag into the receiver config |
|
sharedConfig["features"] = map[string]any{ |
|
"fqdn": map[string]any{ |
|
"enabled": fqdnEnabled, |
|
}, |
|
} |
On the Beat side, libbeat/features already knows how to parse more than just fqdn from a Beat config features block. It also parses log_input_run_as_filestream and aws_s3_v2: https://github.com/elastic/beats/blob/af686c255e1f319b47524835f63b06d31365d47b/libbeat/features/features.go#L52-L67
type cfg struct {
Features struct {
FQDN *conf.C `json:"fqdn" yaml:"fqdn" config:"fqdn"`
LogRunAsFilestream *conf.C `json:"log_input_run_as_filestream" config:"log_input_run_as_filestream"`
AwsS3V2 *conf.C `json:"aws_s3_v2" yaml:"aws_s3_v2" config:"aws_s3_v2"`
} `json:"features" yaml:"features" config:"features"`
}
parsedFlags := cfg{}
if err := c.Unpack(&parsedFlags); err != nil {
return fmt.Errorf("could not unpack features config: %w", err)
}
flags.SetFQDNEnabled(parsedFlags.Features.FQDN.Enabled())
flags.SetLogInputRunFilestream(parsedFlags.Features.LogRunAsFilestream.Enabled())
flags.SetAwsS3V2(parsedFlags.Features.AwsS3V2.Enabled())
Because the translator's generated receiver features map currently contains only fqdn, the other Beat-supported flags do not reach OTel Beat receivers when configured as Agent feature flags.
This is different from the intended feature propagation model used by process-managed Beats. proto.Features only has a concrete typed field for fqdn, but it also carries the raw feature configuration in Source:
|
func (f *Flags) AsProto() *proto.Features { |
|
return &proto.Features{ |
|
Fqdn: &proto.FQDNFeature{ |
|
Enabled: f.FQDN(), |
|
}, |
|
Source: f.source, |
|
} |
That raw source is intentionally used so new feature flags can be propagated without changing the proto schema every time a flag is added.
The OTel translator should follow the same design intent: do not require a hard-coded typed field for every feature flag, and do not special-case only fqdn.
Desired behavior
All feature flags configured under agent.features.* should be propagated consistently to Beat receivers.
Instead of hard-coding only:
the OTel translator should convert the full relevant agent.features.* tree into the Beat receiver features.* tree, preserving feature names and enabled values, for example:
agent:
features:
fqdn:
enabled: true
log_input_run_as_filestream:
enabled: true
aws_s3_v2:
enabled: true
should produce Beat receiver config equivalent to:
features:
fqdn:
enabled: true
log_input_run_as_filestream:
enabled: true
aws_s3_v2:
enabled: true
Acceptance criteria
- The OTel translator no longer hard-codes only
fqdn when building Beat receiver features.
- All supported
agent.features.* entries are passed to generated Beat receiver config under features.*.
- Tests cover propagation of multiple feature flags, not only
fqdn.
- The implementation avoids creating two competing feature flag propagation mechanisms for Beat receivers.
Assisted-by: GPT-5.5
Human reviewed: yes
Problem
Elastic Agent's OTel translator currently handles Beat receiver feature flags inconsistently.
The translator special-cases
agent.features.fqdn.enabledand writes it into the generated Beat receiver config asfeatures.fqdn.enabled. Other feature flags underagent.features.*are not propagated to Beat receivers through the same path, so Beat receiver behavior can diverge from process-managed Beats and from the operator's Agent policy.This means only
fqdncurrently gets first-class treatment in generated Beat receiver configs, while other Beat-supported feature flags such as:agent.features.log_input_run_as_filestream.enabledagent.features.aws_s3_v2.enabledare excluded from the generated receiver
featuresblock unless they are manually present in raw Beat/receiver config.Current behavior
The OTel translator evaluates the Agent FQDN flag once and injects only that flag into each Beat receiver config:
elastic-agent/internal/pkg/otel/translate/otelconfig.go
Lines 78 to 80 in 77a6589
features.fqdn.enabledblock:elastic-agent/internal/pkg/otel/translate/otelconfig.go
Lines 449 to 454 in 77a6589
On the Beat side,
libbeat/featuresalready knows how to parse more than justfqdnfrom a Beat configfeaturesblock. It also parseslog_input_run_as_filestreamandaws_s3_v2: https://github.com/elastic/beats/blob/af686c255e1f319b47524835f63b06d31365d47b/libbeat/features/features.go#L52-L67Because the translator's generated receiver
featuresmap currently contains onlyfqdn, the other Beat-supported flags do not reach OTel Beat receivers when configured as Agent feature flags.This is different from the intended feature propagation model used by process-managed Beats.
proto.Featuresonly has a concrete typed field forfqdn, but it also carries the raw feature configuration inSource:elastic-agent/pkg/features/features.go
Lines 113 to 119 in 77a6589
That raw source is intentionally used so new feature flags can be propagated without changing the proto schema every time a flag is added.
The OTel translator should follow the same design intent: do not require a hard-coded typed field for every feature flag, and do not special-case only
fqdn.Desired behavior
All feature flags configured under
agent.features.*should be propagated consistently to Beat receivers.Instead of hard-coding only:
features.fqdn.enabledthe OTel translator should convert the full relevant
agent.features.*tree into the Beat receiverfeatures.*tree, preserving feature names and enabled values, for example:should produce Beat receiver config equivalent to:
Acceptance criteria
fqdnwhen building Beat receiverfeatures.agent.features.*entries are passed to generated Beat receiver config underfeatures.*.fqdn.Assisted-by: GPT-5.5
Human reviewed: yes