78 lines
1.8 KiB
Go
78 lines
1.8 KiB
Go
// Copyright The OpenTelemetry Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package extensions // import "go.opentelemetry.io/collector/service/extensions"
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"gonum.org/v1/gonum/graph"
|
|
"gonum.org/v1/gonum/graph/simple"
|
|
"gonum.org/v1/gonum/graph/topo"
|
|
|
|
"go.opentelemetry.io/collector/component"
|
|
"go.opentelemetry.io/collector/extension/extensioncapabilities"
|
|
)
|
|
|
|
type node struct {
|
|
nodeID int64
|
|
extID component.ID
|
|
}
|
|
|
|
func (n node) ID() int64 {
|
|
return n.nodeID
|
|
}
|
|
|
|
func computeOrder(exts *Extensions) ([]component.ID, error) {
|
|
graph := simple.NewDirectedGraph()
|
|
nodes := make(map[component.ID]*node)
|
|
for extID := range exts.extMap {
|
|
n := &node{
|
|
nodeID: int64(len(nodes) + 1),
|
|
extID: extID,
|
|
}
|
|
graph.AddNode(n)
|
|
nodes[extID] = n
|
|
}
|
|
for extID, ext := range exts.extMap {
|
|
n := nodes[extID]
|
|
if dep, ok := ext.(extensioncapabilities.Dependent); ok {
|
|
for _, depID := range dep.Dependencies() {
|
|
d, ok := nodes[depID]
|
|
if !ok {
|
|
return nil, fmt.Errorf("unable to find extension %s on which extension %s depends", depID, extID)
|
|
}
|
|
graph.SetEdge(graph.NewEdge(d, n))
|
|
}
|
|
}
|
|
}
|
|
orderedNodes, err := topo.Sort(graph)
|
|
if err != nil {
|
|
return nil, cycleErr(err, topo.DirectedCyclesIn(graph))
|
|
}
|
|
|
|
order := make([]component.ID, len(orderedNodes))
|
|
for i, n := range orderedNodes {
|
|
order[i] = n.(*node).extID
|
|
}
|
|
return order, nil
|
|
}
|
|
|
|
func cycleErr(err error, cycles [][]graph.Node) error {
|
|
var topoErr topo.Unorderable
|
|
if !errors.As(err, &topoErr) || len(cycles) == 0 || len(cycles[0]) == 0 {
|
|
return err
|
|
}
|
|
|
|
cycle := cycles[0]
|
|
var names []string
|
|
for _, n := range cycle {
|
|
node := n.(*node)
|
|
names = append(names, node.extID.String())
|
|
}
|
|
cycleStr := "[" + strings.Join(names, " -> ") + "]"
|
|
return fmt.Errorf("unable to order extensions by dependencies, cycle found %s: %w", cycleStr, err)
|
|
}
|