Skip to content

Commit c392f7e

Browse files
authored
Allow overriding otel exporter and extension configuration for outputs (#10992)
* Allow overriding otel exporter config * Allow overriding otel output extension config * Unskip integration test with override
1 parent 83880d3 commit c392f7e

File tree

3 files changed

+415
-5
lines changed

3 files changed

+415
-5
lines changed

internal/pkg/otel/translate/otelconfig.go

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,13 @@ import (
3636

3737
// This is a prefix we add to all names of Otel entities in the configuration. Its purpose is to avoid collisions with
3838
// user-provided configuration
39-
const OtelNamePrefix = "_agent-component/"
39+
const (
40+
OtelNamePrefix = "_agent-component/"
41+
BeatsAuthExtensionType = "beatsauth"
42+
outputOtelOverrideFieldName = "otel"
43+
outputOtelOverrideExporterFieldName = "exporter"
44+
outputOtelOverrideExtensionsFieldName = "extensions"
45+
)
4046

4147
// BeatMonitoringConfigGetter is a function that returns the monitoring configuration for a beat receiver.
4248
type (
@@ -183,7 +189,7 @@ func getExporterID(exporterType otelcomponent.Type, outputName string) otelcompo
183189
// outputName here is name of the output defined in elastic-agent.yml. For ex: default, monitoring
184190
func getBeatsAuthExtensionID(outputName string) otelcomponent.ID {
185191
extensionName := fmt.Sprintf("%s%s", OtelNamePrefix, outputName)
186-
return otelcomponent.NewIDWithName(otelcomponent.MustNewType("beatsauth"), extensionName)
192+
return otelcomponent.NewIDWithName(otelcomponent.MustNewType(BeatsAuthExtensionType), extensionName)
187193
}
188194

189195
// getCollectorConfigForComponent returns the Otel collector config required to run the given component.
@@ -426,6 +432,12 @@ func unitToExporterConfig(unit component.Unit, exporterType otelcomponent.Type,
426432
return nil, nil, nil, fmt.Errorf("error translating config for output: %s, unit: %s, error: %w", outputName, unit.ID, err)
427433
}
428434

435+
// if there's an otel override config, extract it, we'll apply it after the conversion
436+
otelOverrideCfgC, err := extractOutputOtelOverrideConfig(outputCfgC)
437+
if err != nil {
438+
return nil, nil, nil, err
439+
}
440+
429441
// Config translation function can mutate queue settings defined under output config
430442
exporterConfig, err := configTranslationFunc(outputCfgC, logger)
431443
if err != nil {
@@ -443,6 +455,19 @@ func unitToExporterConfig(unit component.Unit, exporterType otelcomponent.Type,
443455
}
444456
}
445457

458+
// if there's an otel override section for the exporter, we should apply it
459+
exporterOverrideCfg, err := getOutputOtelOverrideExporterConfig(otelOverrideCfgC)
460+
if err != nil {
461+
return nil, nil, nil, err
462+
}
463+
koanfmaps.Merge(exporterOverrideCfg, exporterConfig)
464+
465+
// if there's an otel override section for extensions, extract it and apply it to individual extension configs
466+
extensionsOverrideCfg, err := getOutputOtelOverrideExtensionsConfig(otelOverrideCfgC)
467+
if err != nil {
468+
return nil, nil, nil, err
469+
}
470+
446471
// beatsauth extension is not tested with output other than elasticsearch
447472
if exporterType.String() == "elasticsearch" {
448473
// get extension ID
@@ -452,6 +477,10 @@ func unitToExporterConfig(unit component.Unit, exporterType otelcomponent.Type,
452477
return nil, nil, nil, fmt.Errorf("error supporting http parameters for output: %s, unit: %s, error: %w", outputName, unit.ID, err)
453478
}
454479

480+
if beatsauthOverrideCfg, found := extensionsOverrideCfg[BeatsAuthExtensionType]; found {
481+
koanfmaps.Merge(beatsauthOverrideCfg, extensionConfig)
482+
}
483+
455484
// sets extensionCfg
456485
extensionCfg = map[string]any{
457486
extensionID.String(): extensionConfig,
@@ -519,16 +548,74 @@ func translateEsOutputToExporter(cfg *config.C, logger *logp.Logger) (map[string
519548
if err != nil {
520549
return nil, err
521550
}
522-
// dynamic indexing works by default
523551

524-
// we also want to use dynamic log ids
552+
// we want to use dynamic log ids
525553
esConfig["logs_dynamic_id"] = map[string]any{"enabled": true}
526554

527555
esConfig["include_source_on_error"] = true
528556

529557
return esConfig, nil
530558
}
531559

560+
// extractOutputOtelOverrideConfig removes the configuration under the otel override key from the provided configuration
561+
// and returns it.
562+
func extractOutputOtelOverrideConfig(cfg *config.C) (*config.C, error) {
563+
if !cfg.HasField(outputOtelOverrideFieldName) {
564+
return nil, nil
565+
}
566+
otelCfg, err := cfg.Child(outputOtelOverrideFieldName, -1)
567+
if err != nil {
568+
return nil, err
569+
}
570+
_, err = cfg.Remove(outputOtelOverrideFieldName, -1)
571+
if err != nil {
572+
return nil, err
573+
}
574+
return otelCfg, nil
575+
}
576+
577+
// getOutputOtelOverrideExporterConfig returns the exporter override configuration from the given otel override
578+
// configuration as a map[string]any. It does not modify the input.
579+
func getOutputOtelOverrideExporterConfig(otelOverrideCfg *config.C) (map[string]any, error) {
580+
if otelOverrideCfg == nil {
581+
return nil, nil
582+
}
583+
if !otelOverrideCfg.HasField(outputOtelOverrideExporterFieldName) {
584+
return nil, nil
585+
}
586+
exporterCfgC, err := otelOverrideCfg.Child(outputOtelOverrideExporterFieldName, -1)
587+
if err != nil {
588+
return nil, err
589+
}
590+
exporterCfgMap := make(map[string]any)
591+
err = exporterCfgC.Unpack(&exporterCfgMap)
592+
if err != nil {
593+
return nil, err
594+
}
595+
return exporterCfgMap, nil
596+
}
597+
598+
// getOutputOtelOverrideExporterConfig returns the override configuration for extensions from the given otel override
599+
// configuration. The return value is a map keyed by extension types, with configuration overrides as values.
600+
func getOutputOtelOverrideExtensionsConfig(otelOverrideCfg *config.C) (map[string]map[string]any, error) {
601+
if otelOverrideCfg == nil {
602+
return nil, nil
603+
}
604+
if !otelOverrideCfg.HasField(outputOtelOverrideExtensionsFieldName) {
605+
return nil, nil
606+
}
607+
extensionsCfgC, err := otelOverrideCfg.Child(outputOtelOverrideExtensionsFieldName, -1)
608+
if err != nil {
609+
return nil, err
610+
}
611+
extensionsCfgMap := make(map[string]map[string]any)
612+
err = extensionsCfgC.Unpack(&extensionsCfgMap)
613+
if err != nil {
614+
return nil, err
615+
}
616+
return extensionsCfgMap, nil
617+
}
618+
532619
func BeatDataPath(componentId string) string {
533620
return filepath.Join(paths.Run(), componentId)
534621
}

0 commit comments

Comments
 (0)