@@ -13,7 +13,11 @@ import (
13
13
"sync/atomic"
14
14
"time"
15
15
16
+ << << << < HEAD
16
17
"github.com/elastic/elastic-agent/internal/pkg/otel/translate"
18
+ == == == =
19
+ "github.com/elastic/elastic-agent/internal/pkg/core/backoff"
20
+ >> >> >> > 503421 fc8 (Move beat receiver component logic to the otel manager (#8737 ))
17
21
18
22
"go.opentelemetry.io/collector/component/componentstatus"
19
23
@@ -134,15 +138,22 @@ type RuntimeManager interface {
134
138
PerformComponentDiagnostics (ctx context.Context , additionalMetrics []cproto.AdditionalDiagnosticRequest , req ... component.Component ) ([]runtime.ComponentDiagnostic , error )
135
139
}
136
140
137
- // OTelManager provides an interface to run and update the runtime .
141
+ // OTelManager provides an interface to run components and plain otel configurations in an otel collector .
138
142
type OTelManager interface {
139
143
Runner
140
144
141
- // Update updates the current configuration for OTel .
142
- Update (cfg * confmap.Conf )
145
+ // Update updates the current plain configuration for the otel collector and components .
146
+ Update (* confmap.Conf , []component. Component )
143
147
144
- // Watch returns the chanel to watch for configuration changes.
145
- Watch () <- chan * status.AggregateStatus
148
+ // WatchCollector returns a channel to watch for collector status updates.
149
+ WatchCollector () <- chan * status.AggregateStatus
150
+
151
+ // WatchComponents returns a channel to watch for component state updates.
152
+ WatchComponents () <- chan []runtime.ComponentComponentState
153
+
154
+ // MergedOtelConfig returns the merged Otel collector configuration, containing both the plain config and the
155
+ // component config.
156
+ MergedOtelConfig () * confmap.Conf
146
157
}
147
158
148
159
// ConfigChange provides an interface for receiving a new configuration.
@@ -225,8 +236,6 @@ type Coordinator struct {
225
236
226
237
otelMgr OTelManager
227
238
otelCfg * confmap.Conf
228
- // the final config sent to the manager, contains both config from hybrid mode and from components
229
- finalOtelCfg * confmap.Conf
230
239
231
240
caps capabilities.Capabilities
232
241
modifiers []ComponentsModifier
@@ -349,8 +358,9 @@ type managerChans struct {
349
358
varsManagerUpdate <- chan []* transpiler.Vars
350
359
varsManagerError <- chan error
351
360
352
- otelManagerUpdate chan * status.AggregateStatus
353
- otelManagerError <- chan error
361
+ otelManagerCollectorUpdate <- chan * status.AggregateStatus
362
+ otelManagerComponentUpdate <- chan []runtime.ComponentComponentState
363
+ otelManagerError <- chan error
354
364
355
365
upgradeMarkerUpdate <- chan upgrade.UpdateMarker
356
366
}
@@ -378,7 +388,24 @@ type UpdateComponentChange struct {
378
388
}
379
389
380
390
// New creates a new coordinator.
381
- func New (logger * logger.Logger , cfg * configuration.Configuration , logLevel logp.Level , agentInfo info.Agent , specs component.RuntimeSpecs , reexecMgr ReExecManager , upgradeMgr UpgradeManager , runtimeMgr RuntimeManager , configMgr ConfigManager , varsMgr VarsManager , caps capabilities.Capabilities , monitorMgr MonitorManager , isManaged bool , otelMgr OTelManager , fleetAcker acker.Acker , modifiers ... ComponentsModifier ) * Coordinator {
391
+ func New (
392
+ logger * logger.Logger ,
393
+ cfg * configuration.Configuration ,
394
+ logLevel logp.Level ,
395
+ agentInfo info.Agent ,
396
+ specs component.RuntimeSpecs ,
397
+ reexecMgr ReExecManager ,
398
+ upgradeMgr UpgradeManager ,
399
+ runtimeMgr RuntimeManager ,
400
+ configMgr ConfigManager ,
401
+ varsMgr VarsManager ,
402
+ caps capabilities.Capabilities ,
403
+ monitorMgr MonitorManager ,
404
+ isManaged bool ,
405
+ otelMgr OTelManager ,
406
+ fleetAcker acker.Acker ,
407
+ modifiers ... ComponentsModifier ,
408
+ ) * Coordinator {
382
409
var fleetState cproto.State
383
410
var fleetMessage string
384
411
if ! isManaged {
@@ -465,7 +492,8 @@ func New(logger *logger.Logger, cfg *configuration.Configuration, logLevel logp.
465
492
if otelMgr != nil {
466
493
// The otel manager sends updates to the watchRuntimeComponents function, which extracts component status
467
494
// and forwards the rest to this channel.
468
- c .managerChans .otelManagerUpdate = make (chan * status.AggregateStatus )
495
+ c .managerChans .otelManagerCollectorUpdate = otelMgr .WatchCollector ()
496
+ c .managerChans .otelManagerComponentUpdate = otelMgr .WatchComponents ()
469
497
c .managerChans .otelManagerError = otelMgr .Errors ()
470
498
}
471
499
if upgradeMgr != nil && upgradeMgr .MarkerWatcher () != nil {
@@ -657,70 +685,29 @@ func (c *Coordinator) SetLogLevel(ctx context.Context, lvl *logp.Level) error {
657
685
func (c * Coordinator ) watchRuntimeComponents (
658
686
ctx context.Context ,
659
687
runtimeComponentStates <- chan runtime.ComponentComponentState ,
660
- otelStatuses <- chan * status. AggregateStatus ,
688
+ otelComponentStates <- chan []runtime. ComponentComponentState ,
661
689
) {
662
690
// We need to track otel component state separately because otel components may not always get a STOPPED status
663
691
// If we receive an otel status without the state of a component we're tracking, we need to emit a fake STOPPED
664
692
// status for it. Process component states should not be affected by this logic.
665
- processState := make (map [string ]runtime.ComponentState )
666
- otelState := make (map [string ]runtime.ComponentState )
693
+ state := make (map [string ]runtime.ComponentState )
667
694
668
695
for {
669
696
select {
670
697
case <- ctx .Done ():
671
698
return
672
699
case componentState := <- runtimeComponentStates :
673
- logComponentStateChange (c .logger , processState , & componentState )
700
+ logComponentStateChange (c .logger , state , & componentState )
674
701
// Forward the final changes back to Coordinator, unless our context
675
702
// has ended.
676
703
select {
677
704
case c .managerChans .runtimeManagerUpdate <- componentState :
678
705
case <- ctx .Done ():
679
706
return
680
707
}
681
- case otelStatus := <- otelStatuses :
682
- // We don't break on errors here, because we want to forward the status
683
- // even if there was an error, and the rest of the code gracefully handles componentStates being nil
684
- componentStates , err := translate .GetAllComponentStates (otelStatus , c .componentModel )
685
- if err != nil {
686
- c .setOTelError (err )
687
- }
688
- finalOtelStatus , err := translate .DropComponentStateFromOtelStatus (otelStatus )
689
- if err != nil {
690
- c .setOTelError (err )
691
- finalOtelStatus = otelStatus
692
- }
693
-
694
- // forward the remaining otel status
695
- // TODO: Implement subscriptions for otel manager status to avoid the need for this
696
- select {
697
- case c .managerChans .otelManagerUpdate <- finalOtelStatus :
698
- case <- ctx .Done ():
699
- return
700
- }
701
-
702
- // drop component states which don't exist in the configuration anymore
703
- // we need to do this because we aren't guaranteed to receive a STOPPED state when the component is removed
704
- componentIds := make (map [string ]bool )
705
- for _ , componentState := range componentStates {
706
- componentIds [componentState .Component .ID ] = true
707
- }
708
- for id := range otelState {
709
- if _ , ok := componentIds [id ]; ! ok {
710
- // this component is not in the configuration anymore, emit a fake STOPPED state
711
- componentStates = append (componentStates , runtime.ComponentComponentState {
712
- Component : component.Component {
713
- ID : id ,
714
- },
715
- State : runtime.ComponentState {
716
- State : client .UnitStateStopped ,
717
- },
718
- })
719
- }
720
- }
721
- // now handle the component states
708
+ case componentStates := <- otelComponentStates :
722
709
for _ , componentState := range componentStates {
723
- logComponentStateChange (c .logger , otelState , & componentState )
710
+ logComponentStateChange (c .logger , state , & componentState )
724
711
// Forward the final changes back to Coordinator, unless our context
725
712
// has ended.
726
713
select {
@@ -813,15 +800,15 @@ func (c *Coordinator) Run(ctx context.Context) error {
813
800
defer watchCanceller ()
814
801
815
802
var subChan <- chan runtime.ComponentComponentState
816
- var otelChan <- chan * status. AggregateStatus
803
+ var otelChan <- chan []runtime. ComponentComponentState
817
804
// A real Coordinator will always have a runtime manager, but unit tests
818
805
// may not initialize all managers -- in that case we leave subChan nil,
819
806
// and just idle until Coordinator shuts down.
820
807
if c .runtimeMgr != nil {
821
808
subChan = c .runtimeMgr .SubscribeAll (ctx ).Ch ()
822
809
}
823
810
if c .otelMgr != nil {
824
- otelChan = c .otelMgr .Watch ()
811
+ otelChan = c .otelMgr .WatchComponents ()
825
812
}
826
813
go c .watchRuntimeComponents (watchCtx , subChan , otelChan )
827
814
@@ -1117,10 +1104,11 @@ func (c *Coordinator) DiagnosticHooks() diagnostics.Hooks {
1117
1104
Description : "Final otel configuration used by the Elastic Agent. Includes hybrid mode config and component config." ,
1118
1105
ContentType : "application/yaml" ,
1119
1106
Hook : func (_ context.Context ) []byte {
1120
- if c .finalOtelCfg == nil {
1107
+ mergedCfg := c .otelMgr .MergedOtelConfig ()
1108
+ if mergedCfg == nil {
1121
1109
return []byte ("no active OTel configuration" )
1122
1110
}
1123
- o , err := yaml .Marshal (c . finalOtelCfg .ToStringMap ())
1111
+ o , err := yaml .Marshal (mergedCfg .ToStringMap ())
1124
1112
if err != nil {
1125
1113
return []byte (fmt .Sprintf ("error: failed to convert to yaml: %v" , err ))
1126
1114
}
@@ -1314,7 +1302,7 @@ func (c *Coordinator) runLoopIteration(ctx context.Context) {
1314
1302
c .processVars (ctx , vars )
1315
1303
}
1316
1304
1317
- case collectorStatus := <- c .managerChans .otelManagerUpdate :
1305
+ case collectorStatus := <- c .managerChans .otelManagerCollectorUpdate :
1318
1306
c .state .Collector = collectorStatus
1319
1307
c .stateNeedsRefresh = true
1320
1308
@@ -1532,58 +1520,25 @@ func (c *Coordinator) refreshComponentModel(ctx context.Context) (err error) {
1532
1520
1533
1521
c .logger .Info ("Updating running component model" )
1534
1522
c .logger .With ("components" , model .Components ).Debug ("Updating running component model" )
1535
- return c .updateManagersWithConfig (model )
1523
+ c .updateManagersWithConfig (model )
1524
+ return nil
1536
1525
}
1537
1526
1538
1527
// updateManagersWithConfig updates runtime managers with the component model and config.
1539
1528
// Components may be sent to different runtimes depending on various criteria.
1540
- func (c * Coordinator ) updateManagersWithConfig (model * component.Model ) error {
1529
+ func (c * Coordinator ) updateManagersWithConfig (model * component.Model ) {
1541
1530
runtimeModel , otelModel := c .splitModelBetweenManagers (model )
1542
1531
c .logger .With ("components" , runtimeModel .Components ).Debug ("Updating runtime manager model" )
1543
1532
c .runtimeMgr .Update (* runtimeModel )
1544
- return c .updateOtelManagerConfig (otelModel )
1545
- }
1546
-
1547
- // updateOtelManagerConfig updates the otel collector configuration for the otel manager. It assembles this configuration
1548
- // from the component model passed in and from the hybrid-mode otel config set on the Coordinator.
1549
- func (c * Coordinator ) updateOtelManagerConfig (model * component.Model ) error {
1550
- finalOtelCfg := confmap .New ()
1551
- var componentOtelCfg * confmap.Conf
1552
- if len (model .Components ) > 0 {
1553
- var err error
1554
- c .logger .With ("components" , model .Components ).Debug ("Updating otel manager model" )
1555
- componentOtelCfg , err = translate .GetOtelConfig (model , c .agentInfo , c .monitorMgr .ComponentMonitoringConfig )
1556
- if err != nil {
1557
- c .logger .Errorf ("failed to generate otel config: %v" , err )
1558
- }
1559
- componentIDs := make ([]string , 0 , len (model .Components ))
1560
- for _ , comp := range model .Components {
1533
+ c .logger .With ("components" , otelModel .Components ).Debug ("Updating otel manager model" )
1534
+ if len (otelModel .Components ) > 0 {
1535
+ componentIDs := make ([]string , 0 , len (otelModel .Components ))
1536
+ for _ , comp := range otelModel .Components {
1561
1537
componentIDs = append (componentIDs , comp .ID )
1562
1538
}
1563
1539
c .logger .With ("component_ids" , componentIDs ).Warn ("The Otel runtime manager is HIGHLY EXPERIMENTAL and only intended for testing. Use at your own risk." )
1564
1540
}
1565
- if componentOtelCfg != nil {
1566
- err := finalOtelCfg .Merge (componentOtelCfg )
1567
- if err != nil {
1568
- c .logger .Error ("failed to merge otel config: %v" , err )
1569
- }
1570
- }
1571
-
1572
- if c .otelCfg != nil {
1573
- err := finalOtelCfg .Merge (c .otelCfg )
1574
- if err != nil {
1575
- c .logger .Error ("failed to merge otel config: %v" , err )
1576
- }
1577
- }
1578
-
1579
- if len (finalOtelCfg .AllKeys ()) == 0 {
1580
- // if the config is empty, we want to send nil to the manager, so it knows to stop the collector
1581
- finalOtelCfg = nil
1582
- }
1583
-
1584
- c .otelMgr .Update (finalOtelCfg )
1585
- c .finalOtelCfg = finalOtelCfg
1586
- return nil
1541
+ c .otelMgr .Update (c .otelCfg , otelModel .Components )
1587
1542
}
1588
1543
1589
1544
// splitModelBetweenManager splits the model components between the runtime manager and the otel manager.
0 commit comments