Skip to content

Commit

Permalink
Infer metadata automatically
Browse files Browse the repository at this point in the history
  • Loading branch information
thampiotr committed Nov 15, 2023
1 parent 9609d29 commit 9bfcf7a
Show file tree
Hide file tree
Showing 75 changed files with 1,516 additions and 138 deletions.
7 changes: 3 additions & 4 deletions component/discovery/aws/ec2.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ import (

func init() {
component.Register(component.Registration{
Name: "discovery.ec2",
Args: EC2Arguments{},
Exports: discovery.Exports{},
Metadata: component.TargetDiscoveryMetadata(),
Name: "discovery.ec2",
Args: EC2Arguments{},
Exports: discovery.Exports{},
Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
return NewEC2(opts, args.(EC2Arguments))
},
Expand Down
7 changes: 3 additions & 4 deletions component/discovery/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ import (

func init() {
component.Register(component.Registration{
Name: "discovery.kubernetes",
Args: Arguments{},
Exports: discovery.Exports{},
Metadata: component.TargetDiscoveryMetadata(),
Name: "discovery.kubernetes",
Args: Arguments{},
Exports: discovery.Exports{},

Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
return New(opts, args.(Arguments))
Expand Down
7 changes: 3 additions & 4 deletions component/discovery/relabel/relabel.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ import (

func init() {
component.Register(component.Registration{
Name: "discovery.relabel",
Args: Arguments{},
Exports: Exports{},
Metadata: component.TargetsProcessingMetadata(),
Name: "discovery.relabel",
Args: Arguments{},
Exports: Exports{},

Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
return New(opts, args.(Arguments))
Expand Down
7 changes: 3 additions & 4 deletions component/loki/echo/echo.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ import (

func init() {
component.Register(component.Registration{
Name: "loki.echo",
Args: Arguments{},
Exports: Exports{},
Metadata: component.LokiLogsSinkMetadata(),
Name: "loki.echo",
Args: Arguments{},
Exports: Exports{},

Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
return New(opts, args.(Arguments))
Expand Down
7 changes: 3 additions & 4 deletions component/loki/process/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ import (

func init() {
component.Register(component.Registration{
Name: "loki.process",
Args: Arguments{},
Exports: Exports{},
Metadata: component.LokiLogsProcessingMetadata(),
Name: "loki.process",
Args: Arguments{},
Exports: Exports{},
Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
return New(opts, args.(Arguments))
},
Expand Down
7 changes: 3 additions & 4 deletions component/loki/relabel/relabel.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ import (

func init() {
component.Register(component.Registration{
Name: "loki.relabel",
Args: Arguments{},
Exports: Exports{},
Metadata: component.LokiLogsProcessingMetadata(),
Name: "loki.relabel",
Args: Arguments{},
Exports: Exports{},
Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
return New(opts, args.(Arguments))
},
Expand Down
5 changes: 2 additions & 3 deletions component/loki/source/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ import (

func init() {
component.Register(component.Registration{
Name: "loki.source.api",
Args: Arguments{},
Metadata: component.LokiLogsSourceMetadata(),
Name: "loki.source.api",
Args: Arguments{},
Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
return New(opts, args.(Arguments))
},
Expand Down
5 changes: 2 additions & 3 deletions component/loki/source/file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ import (

func init() {
component.Register(component.Registration{
Name: "loki.source.file",
Args: Arguments{},
Metadata: component.LokiLogsScraperMetadata(),
Name: "loki.source.file",
Args: Arguments{},

Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
return New(opts, args.(Arguments))
Expand Down
5 changes: 2 additions & 3 deletions component/loki/source/gcplog/gcplog.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ import (

func init() {
component.Register(component.Registration{
Name: "loki.source.gcplog",
Args: Arguments{},
Metadata: component.LokiLogsSourceMetadata(),
Name: "loki.source.gcplog",
Args: Arguments{},

Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
return New(opts, args.(Arguments))
Expand Down
7 changes: 3 additions & 4 deletions component/loki/write/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ import (

func init() {
component.Register(component.Registration{
Name: "loki.write",
Args: Arguments{},
Exports: Exports{},
Metadata: component.LokiLogsSinkMetadata(),
Name: "loki.write",
Args: Arguments{},
Exports: Exports{},

Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
return New(opts, args.(Arguments))
Expand Down
65 changes: 0 additions & 65 deletions component/metadata.go

This file was deleted.

110 changes: 110 additions & 0 deletions component/metadata/metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package metadata

import (
"fmt"
"reflect"

"github.com/grafana/agent/component"
_ "github.com/grafana/agent/component/all"
"github.com/grafana/agent/component/common/loki"
"github.com/grafana/agent/component/discovery"
)

type DataType string

var (
// DataTypeTargets represents things that need to be scraped. These are used by multiple telemetry signals
// scraping components and often require special labels, e.g. __path__ label is required for scraping
// logs from files using loki.source.file component.
DataTypeTargets = DataType("Targets")

// DataTypeLokiLogs represent logs in Loki format
DataTypeLokiLogs = DataType("Loki Logs")

DataTypeOTELTelemetry = DataType("OTEL Telemetry")
DataTypePromMetrics = DataType("Prometheus Metrics")
DataTypePyroscopeProfiles = DataType("Pyroscope Profiles")
)

type Metadata struct {
Accepts []DataType
Outputs []DataType
}

func (m Metadata) Empty() bool {
return len(m.Accepts) == 0 && len(m.Outputs) == 0
}

func ForComponent(name string) (Metadata, error) {
reg, ok := component.Get(name)
if !ok {
return Metadata{}, fmt.Errorf("could not find component %q", name)
}
return inferMetadata(reg.Args, reg.Exports), nil
}

func inferMetadata(args component.Arguments, exports component.Exports) Metadata {
var accepts []DataType
var outputs []DataType

if exports != nil {
if hasFieldOfType(exports, reflect.TypeOf(loki.NewLogsReceiver())) {
accepts = append(accepts, DataTypeLokiLogs)
}
if hasFieldOfType(exports, reflect.TypeOf([]discovery.Target{})) {
outputs = append(outputs, DataTypeTargets)
}
}

if args != nil {
if hasFieldOfType(args, reflect.TypeOf([]discovery.Target{})) {
accepts = append(accepts, DataTypeTargets)
}
// Components that have e.g. `ForwardsTo []loki.LogsReceiver` arguments, typically output logs
if hasFieldOfType(args, reflect.TypeOf([]loki.LogsReceiver{})) {
outputs = append(outputs, DataTypeLokiLogs)
}
}

return Metadata{
Accepts: accepts,
Outputs: outputs,
}
}

func hasFieldOfType(obj interface{}, fieldType reflect.Type) bool {
objValue := reflect.ValueOf(obj)

// If the object is a pointer, dereference it
for objValue.Kind() == reflect.Ptr {
objValue = objValue.Elem()
}

// If the object is not a struct or interface, return false
if objValue.Kind() != reflect.Struct && objValue.Kind() != reflect.Interface {
return false
}

for i := 0; i < objValue.NumField(); i++ {
fv := objValue.Field(i)
ft := fv.Type()

// If the field type matches the given type, return true
if ft == fieldType {
return true
}

if fv.Kind() == reflect.Interface && fieldType.AssignableTo(ft) {
return true
}

// If the field is a struct, recursively check its fields
if fv.Kind() == reflect.Struct {
if hasFieldOfType(fv.Interface(), fieldType) {
return true
}
}
}

return false
}
51 changes: 51 additions & 0 deletions component/metadata/metadata_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package metadata

import (
"testing"

"github.com/stretchr/testify/require"
)

func Test_inferMetadata(t *testing.T) {
tests := []struct {
name string
expected Metadata
}{
{
name: "discovery.dns",
expected: Metadata{Outputs: []DataType{DataTypeTargets}},
},
{
name: "discovery.relabel",
expected: Metadata{
Accepts: []DataType{DataTypeTargets},
Outputs: []DataType{DataTypeTargets},
},
},
{
name: "loki.echo",
expected: Metadata{Accepts: []DataType{DataTypeLokiLogs}},
},
{
name: "loki.source.file",
expected: Metadata{
Accepts: []DataType{DataTypeTargets},
Outputs: []DataType{DataTypeLokiLogs},
},
},
{
name: "loki.process",
expected: Metadata{
Accepts: []DataType{DataTypeLokiLogs},
Outputs: []DataType{DataTypeLokiLogs},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actual, err := ForComponent(tt.name)
require.NoError(t, err)
require.Equal(t, tt.expected, actual)
})
}
}
4 changes: 0 additions & 4 deletions component/otelcol/exporter/loki/loki.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ func init() {
Name: "otelcol.exporter.loki",
Args: Arguments{},
Exports: otelcol.ConsumerExports{},
Metadata: component.Metadata{
Accepts: []component.DataType{component.DataTypeOTELTelemetry},
Outputs: []component.DataType{component.DataTypeLokiLogs},
},

Build: func(o component.Options, a component.Arguments) (component.Component, error) {
return New(o, a.(Arguments))
Expand Down
4 changes: 0 additions & 4 deletions component/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,6 @@ type Registration struct {
// A component which does not expose exports must leave this set to nil.
Exports Exports

// Component metadata that can be used to validate pipelines or generate
// documentation.
Metadata Metadata

// NeedsServices holds the set of service names which this component depends
// on to run. If NeedsServices includes an invalid service name (either
// because of a cyclic dependency or the named service doesn't exist),
Expand Down
2 changes: 1 addition & 1 deletion docs/docs_updated_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

"github.com/grafana/agent/component"
_ "github.com/grafana/agent/component/all"
"github.com/grafana/agent/docs/sources/generator"
"github.com/grafana/agent/docs/generator"
"github.com/stretchr/testify/require"
)

Expand Down
Loading

0 comments on commit 9bfcf7a

Please sign in to comment.