opentelemetry-collector/service/internal/builders/connector.go

400 lines
14 KiB
Go

// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package builders // import "go.opentelemetry.io/collector/service/internal/builders"
import (
"context"
"fmt"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/connector"
"go.opentelemetry.io/collector/connector/connectortest"
"go.opentelemetry.io/collector/connector/xconnector"
"go.opentelemetry.io/collector/consumer"
"go.opentelemetry.io/collector/consumer/xconsumer"
"go.opentelemetry.io/collector/pipeline"
"go.opentelemetry.io/collector/pipeline/xpipeline"
)
func errDataTypes(id component.ID, from, to pipeline.Signal) error {
return fmt.Errorf("connector %q cannot connect from %s to %s: %w", id, from, to, pipeline.ErrSignalNotSupported)
}
// ConnectorBuilder is a helper struct that given a set of Configs and Factories helps with creating connectors.
type ConnectorBuilder struct {
cfgs map[component.ID]component.Config
factories map[component.Type]connector.Factory
}
// NewConnector creates a new ConnectorBuilder to help with creating components form a set of configs and factories.
func NewConnector(cfgs map[component.ID]component.Config, factories map[component.Type]connector.Factory) *ConnectorBuilder {
return &ConnectorBuilder{cfgs: cfgs, factories: factories}
}
// CreateTracesToTraces creates a Traces connector based on the settings and config.
func (b *ConnectorBuilder) CreateTracesToTraces(ctx context.Context, set connector.Settings, next consumer.Traces) (connector.Traces, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
f, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
logStabilityLevel(set.Logger, f.TracesToTracesStability())
return f.CreateTracesToTraces(ctx, set, cfg, next)
}
// CreateTracesToMetrics creates a Traces connector based on the settings and config.
func (b *ConnectorBuilder) CreateTracesToMetrics(ctx context.Context, set connector.Settings, next consumer.Metrics) (connector.Traces, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
f, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
logStabilityLevel(set.Logger, f.TracesToMetricsStability())
return f.CreateTracesToMetrics(ctx, set, cfg, next)
}
// CreateTracesToLogs creates a Traces connector based on the settings and config.
func (b *ConnectorBuilder) CreateTracesToLogs(ctx context.Context, set connector.Settings, next consumer.Logs) (connector.Traces, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
f, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
logStabilityLevel(set.Logger, f.TracesToLogsStability())
return f.CreateTracesToLogs(ctx, set, cfg, next)
}
// CreateTracesToProfiles creates a Traces connector based on the settings and config.
func (b *ConnectorBuilder) CreateTracesToProfiles(ctx context.Context, set connector.Settings, next xconsumer.Profiles) (connector.Traces, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
connFact, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
f, ok := connFact.(xconnector.Factory)
if !ok {
return nil, errDataTypes(set.ID, pipeline.SignalTraces, xpipeline.SignalProfiles)
}
logStabilityLevel(set.Logger, f.TracesToProfilesStability())
return f.CreateTracesToProfiles(ctx, set, cfg, next)
}
// CreateMetricsToTraces creates a Metrics connector based on the settings and config.
func (b *ConnectorBuilder) CreateMetricsToTraces(ctx context.Context, set connector.Settings, next consumer.Traces) (connector.Metrics, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
f, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
logStabilityLevel(set.Logger, f.MetricsToTracesStability())
return f.CreateMetricsToTraces(ctx, set, cfg, next)
}
// CreateMetricsToMetrics creates a Metrics connector based on the settings and config.
func (b *ConnectorBuilder) CreateMetricsToMetrics(ctx context.Context, set connector.Settings, next consumer.Metrics) (connector.Metrics, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
f, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
logStabilityLevel(set.Logger, f.MetricsToMetricsStability())
return f.CreateMetricsToMetrics(ctx, set, cfg, next)
}
// CreateMetricsToLogs creates a Metrics connector based on the settings and config.
func (b *ConnectorBuilder) CreateMetricsToLogs(ctx context.Context, set connector.Settings, next consumer.Logs) (connector.Metrics, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
f, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
logStabilityLevel(set.Logger, f.MetricsToLogsStability())
return f.CreateMetricsToLogs(ctx, set, cfg, next)
}
// CreateMetricsToProfiles creates a Metrics connector based on the settings and config.
func (b *ConnectorBuilder) CreateMetricsToProfiles(ctx context.Context, set connector.Settings, next xconsumer.Profiles) (connector.Metrics, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
connFact, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
f, ok := connFact.(xconnector.Factory)
if !ok {
return nil, errDataTypes(set.ID, pipeline.SignalMetrics, xpipeline.SignalProfiles)
}
logStabilityLevel(set.Logger, f.MetricsToProfilesStability())
return f.CreateMetricsToProfiles(ctx, set, cfg, next)
}
// CreateLogsToTraces creates a Logs connector based on the settings and config.
func (b *ConnectorBuilder) CreateLogsToTraces(ctx context.Context, set connector.Settings, next consumer.Traces) (connector.Logs, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
f, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
logStabilityLevel(set.Logger, f.LogsToTracesStability())
return f.CreateLogsToTraces(ctx, set, cfg, next)
}
// CreateLogsToMetrics creates a Logs connector based on the settings and config.
func (b *ConnectorBuilder) CreateLogsToMetrics(ctx context.Context, set connector.Settings, next consumer.Metrics) (connector.Logs, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
f, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
logStabilityLevel(set.Logger, f.LogsToMetricsStability())
return f.CreateLogsToMetrics(ctx, set, cfg, next)
}
// CreateLogsToLogs creates a Logs connector based on the settings and config.
func (b *ConnectorBuilder) CreateLogsToLogs(ctx context.Context, set connector.Settings, next consumer.Logs) (connector.Logs, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
f, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
logStabilityLevel(set.Logger, f.LogsToLogsStability())
return f.CreateLogsToLogs(ctx, set, cfg, next)
}
// CreateLogsToProfiles creates a Logs connector based on the settings and config.
func (b *ConnectorBuilder) CreateLogsToProfiles(ctx context.Context, set connector.Settings, next xconsumer.Profiles) (connector.Logs, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
connFact, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
f, ok := connFact.(xconnector.Factory)
if !ok {
return nil, errDataTypes(set.ID, pipeline.SignalLogs, xpipeline.SignalProfiles)
}
logStabilityLevel(set.Logger, f.LogsToProfilesStability())
return f.CreateLogsToProfiles(ctx, set, cfg, next)
}
// CreateProfilesToTraces creates a Profiles connector based on the settings and config.
func (b *ConnectorBuilder) CreateProfilesToTraces(ctx context.Context, set connector.Settings, next consumer.Traces) (xconnector.Profiles, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
connFact, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
f, ok := connFact.(xconnector.Factory)
if !ok {
return nil, errDataTypes(set.ID, xpipeline.SignalProfiles, pipeline.SignalTraces)
}
logStabilityLevel(set.Logger, f.ProfilesToTracesStability())
return f.CreateProfilesToTraces(ctx, set, cfg, next)
}
// CreateProfilesToMetrics creates a Profiles connector based on the settings and config.
func (b *ConnectorBuilder) CreateProfilesToMetrics(ctx context.Context, set connector.Settings, next consumer.Metrics) (xconnector.Profiles, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
connFact, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
f, ok := connFact.(xconnector.Factory)
if !ok {
return nil, errDataTypes(set.ID, xpipeline.SignalProfiles, pipeline.SignalMetrics)
}
logStabilityLevel(set.Logger, f.ProfilesToMetricsStability())
return f.CreateProfilesToMetrics(ctx, set, cfg, next)
}
// CreateProfilesToLogs creates a Profiles connector based on the settings and config.
func (b *ConnectorBuilder) CreateProfilesToLogs(ctx context.Context, set connector.Settings, next consumer.Logs) (xconnector.Profiles, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
connFact, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
f, ok := connFact.(xconnector.Factory)
if !ok {
return nil, errDataTypes(set.ID, xpipeline.SignalProfiles, pipeline.SignalLogs)
}
logStabilityLevel(set.Logger, f.ProfilesToLogsStability())
return f.CreateProfilesToLogs(ctx, set, cfg, next)
}
// CreateProfilesToProfiles creates a Profiles connector based on the settings and config.
func (b *ConnectorBuilder) CreateProfilesToProfiles(ctx context.Context, set connector.Settings, next xconsumer.Profiles) (xconnector.Profiles, error) {
if next == nil {
return nil, errNilNextConsumer
}
cfg, existsCfg := b.cfgs[set.ID]
if !existsCfg {
return nil, fmt.Errorf("connector %q is not configured", set.ID)
}
connFact, existsFactory := b.factories[set.ID.Type()]
if !existsFactory {
return nil, fmt.Errorf("connector factory not available for: %q", set.ID)
}
f, ok := connFact.(xconnector.Factory)
if !ok {
return nil, errDataTypes(set.ID, xpipeline.SignalProfiles, xpipeline.SignalProfiles)
}
logStabilityLevel(set.Logger, f.ProfilesToProfilesStability())
return f.CreateProfilesToProfiles(ctx, set, cfg, next)
}
func (b *ConnectorBuilder) IsConfigured(componentID component.ID) bool {
_, ok := b.cfgs[componentID]
return ok
}
func (b *ConnectorBuilder) Factory(componentType component.Type) component.Factory {
return b.factories[componentType]
}
// NewNopConnectorConfigsAndFactories returns a configuration and factories that allows building a new nop connector.
func NewNopConnectorConfigsAndFactories() (map[component.ID]component.Config, map[component.Type]connector.Factory) {
nopFactory := connectortest.NewNopFactory()
// Use a different ID than receivertest and exportertest to avoid ambiguous
// configuration scenarios. Ambiguous IDs are detected in the 'otelcol' package,
// but lower level packages such as 'service' assume that IDs are disambiguated.
connID := component.NewIDWithName(NopType, "conn")
configs := map[component.ID]component.Config{
connID: nopFactory.CreateDefaultConfig(),
}
factories := map[component.Type]connector.Factory{
NopType: nopFactory,
}
return configs, factories
}