github.com/Jeffail/benthos/v3@v3.65.0/lib/output/constructor.go (about)

     1  package output
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/Jeffail/benthos/v3/internal/component/output"
     7  	"github.com/Jeffail/benthos/v3/internal/docs"
     8  	"github.com/Jeffail/benthos/v3/internal/interop"
     9  	"github.com/Jeffail/benthos/v3/lib/log"
    10  	"github.com/Jeffail/benthos/v3/lib/metrics"
    11  	"github.com/Jeffail/benthos/v3/lib/output/writer"
    12  	"github.com/Jeffail/benthos/v3/lib/pipeline"
    13  	"github.com/Jeffail/benthos/v3/lib/processor"
    14  	"github.com/Jeffail/benthos/v3/lib/types"
    15  	"github.com/Jeffail/benthos/v3/lib/util/config"
    16  	"gopkg.in/yaml.v3"
    17  )
    18  
    19  //------------------------------------------------------------------------------
    20  
    21  // Category describes the general category of an output.
    22  type Category string
    23  
    24  // Output categories
    25  var (
    26  	CategoryLocal    Category = "Local"
    27  	CategoryAWS      Category = "AWS"
    28  	CategoryGCP      Category = "GCP"
    29  	CategoryAzure    Category = "Azure"
    30  	CategoryServices Category = "Services"
    31  	CategoryNetwork  Category = "Network"
    32  	CategoryUtility  Category = "Utility"
    33  )
    34  
    35  // TypeSpec is a constructor and a usage description for each output type.
    36  type TypeSpec struct {
    37  	constructor ConstructorFunc
    38  
    39  	// Async indicates whether this output benefits from sending multiple
    40  	// messages asynchronously over the protocol.
    41  	Async bool
    42  
    43  	// Batches indicates whether this output benefits from batching of messages.
    44  	Batches bool
    45  
    46  	Status      docs.Status
    47  	Summary     string
    48  	Description string
    49  	Categories  []Category
    50  	Footnotes   string
    51  	config      docs.FieldSpec
    52  	FieldSpecs  docs.FieldSpecs
    53  	Examples    []docs.AnnotatedExample
    54  	Version     string
    55  }
    56  
    57  // AppendProcessorsFromConfig takes a variant arg of pipeline constructor
    58  // functions and returns a new slice of them where the processors of the
    59  // provided output configuration will also be initialized.
    60  func AppendProcessorsFromConfig(
    61  	conf Config,
    62  	mgr types.Manager,
    63  	log log.Modular,
    64  	stats metrics.Type,
    65  	pipelines ...types.PipelineConstructorFunc,
    66  ) []types.PipelineConstructorFunc {
    67  	if len(conf.Processors) > 0 {
    68  		pipelines = append(pipelines, []types.PipelineConstructorFunc{func(i *int) (types.Pipeline, error) {
    69  			if i == nil {
    70  				procs := 0
    71  				i = &procs
    72  			}
    73  			processors := make([]types.Processor, len(conf.Processors))
    74  			for j, procConf := range conf.Processors {
    75  				pMgr, pLog, pMetrics := interop.LabelChild(fmt.Sprintf("processor.%v", *i), mgr, log, stats)
    76  				var err error
    77  				processors[j], err = processor.New(procConf, pMgr, pLog, pMetrics)
    78  				if err != nil {
    79  					return nil, fmt.Errorf("failed to create processor '%v': %v", procConf.Type, err)
    80  				}
    81  				*i++
    82  			}
    83  			return pipeline.NewProcessor(log, stats, processors...), nil
    84  		}}...)
    85  	}
    86  	return pipelines
    87  }
    88  
    89  func fromSimpleConstructor(fn func(Config, types.Manager, log.Modular, metrics.Type) (Type, error)) ConstructorFunc {
    90  	return func(
    91  		conf Config,
    92  		mgr types.Manager,
    93  		log log.Modular,
    94  		stats metrics.Type,
    95  		pipelines ...types.PipelineConstructorFunc,
    96  	) (Type, error) {
    97  		output, err := fn(conf, mgr, log, stats)
    98  		if err != nil {
    99  			return nil, fmt.Errorf("failed to create output '%v': %w", conf.Type, err)
   100  		}
   101  		pipelines = AppendProcessorsFromConfig(conf, mgr, log, stats, pipelines...)
   102  		return WrapWithPipelines(output, pipelines...)
   103  	}
   104  }
   105  
   106  // ConstructorFunc is a func signature able to construct an output.
   107  type ConstructorFunc func(Config, types.Manager, log.Modular, metrics.Type, ...types.PipelineConstructorFunc) (Type, error)
   108  
   109  // WalkConstructors iterates each component constructor.
   110  func WalkConstructors(fn func(ConstructorFunc, docs.ComponentSpec)) {
   111  	inferred := docs.ComponentFieldsFromConf(NewConfig())
   112  	for k, v := range Constructors {
   113  		conf := v.config
   114  		if len(v.FieldSpecs) > 0 {
   115  			conf = docs.FieldComponent().WithChildren(v.FieldSpecs.DefaultAndTypeFrom(inferred[k])...)
   116  		} else {
   117  			conf.Children = conf.Children.DefaultAndTypeFrom(inferred[k])
   118  		}
   119  		spec := docs.ComponentSpec{
   120  			Type:        docs.TypeOutput,
   121  			Name:        k,
   122  			Summary:     v.Summary,
   123  			Description: v.Description,
   124  			Footnotes:   v.Footnotes,
   125  			Config:      conf,
   126  			Examples:    v.Examples,
   127  			Status:      v.Status,
   128  			Version:     v.Version,
   129  		}
   130  		if len(v.Categories) > 0 {
   131  			spec.Categories = make([]string, 0, len(v.Categories))
   132  			for _, cat := range v.Categories {
   133  				spec.Categories = append(spec.Categories, string(cat))
   134  			}
   135  		}
   136  		spec.Description = output.Description(v.Async, v.Batches, spec.Description)
   137  		fn(v.constructor, spec)
   138  	}
   139  	for k, v := range pluginSpecs {
   140  		spec := docs.ComponentSpec{
   141  			Type:   docs.TypeOutput,
   142  			Name:   k,
   143  			Status: docs.StatusExperimental,
   144  			Plugin: true,
   145  			Config: docs.FieldComponent().Unlinted(),
   146  		}
   147  		fn(v.constructor, spec)
   148  	}
   149  }
   150  
   151  // Constructors is a map of all output types with their specs.
   152  var Constructors = map[string]TypeSpec{}
   153  
   154  //------------------------------------------------------------------------------
   155  
   156  // String constants representing each output type.
   157  // Deprecated: Do not add new components here. Instead, use the public plugin
   158  // APIs. Examples can be found in: ./internal/impl
   159  const (
   160  	TypeAMQP               = "amqp"
   161  	TypeAMQP09             = "amqp_0_9"
   162  	TypeAMQP1              = "amqp_1"
   163  	TypeAWSDynamoDB        = "aws_dynamodb"
   164  	TypeAWSKinesis         = "aws_kinesis"
   165  	TypeAWSKinesisFirehose = "aws_kinesis_firehose"
   166  	TypeAWSS3              = "aws_s3"
   167  	TypeAWSSNS             = "aws_sns"
   168  	TypeAWSSQS             = "aws_sqs"
   169  	TypeAzureBlobStorage   = "azure_blob_storage"
   170  	TypeAzureQueueStorage  = "azure_queue_storage"
   171  	TypeAzureTableStorage  = "azure_table_storage"
   172  	TypeBlobStorage        = "blob_storage"
   173  	TypeBroker             = "broker"
   174  	TypeCache              = "cache"
   175  	TypeCassandra          = "cassandra"
   176  	TypeDrop               = "drop"
   177  	TypeDropOn             = "drop_on"
   178  	TypeDropOnError        = "drop_on_error"
   179  	TypeDynamic            = "dynamic"
   180  	TypeDynamoDB           = "dynamodb"
   181  	TypeElasticsearch      = "elasticsearch"
   182  	TypeFallback           = "fallback"
   183  	TypeFile               = "file"
   184  	TypeFiles              = "files"
   185  	TypeGCPCloudStorage    = "gcp_cloud_storage"
   186  	TypeGCPPubSub          = "gcp_pubsub"
   187  	TypeHDFS               = "hdfs"
   188  	TypeHTTPClient         = "http_client"
   189  	TypeHTTPServer         = "http_server"
   190  	TypeInproc             = "inproc"
   191  	TypeKafka              = "kafka"
   192  	TypeKinesis            = "kinesis"
   193  	TypeKinesisFirehose    = "kinesis_firehose"
   194  	TypeMongoDB            = "mongodb"
   195  	TypeMQTT               = "mqtt"
   196  	TypeNanomsg            = "nanomsg"
   197  	TypeNATS               = "nats"
   198  	TypeNATSJetStream      = "nats_jetstream"
   199  	TypeNATSStream         = "nats_stream"
   200  	TypeNSQ                = "nsq"
   201  	TypePulsar             = "pulsar"
   202  	TypeRedisHash          = "redis_hash"
   203  	TypeRedisList          = "redis_list"
   204  	TypeRedisPubSub        = "redis_pubsub"
   205  	TypeRedisStreams       = "redis_streams"
   206  	TypeReject             = "reject"
   207  	TypeResource           = "resource"
   208  	TypeRetry              = "retry"
   209  	TypeS3                 = "s3"
   210  	TypeSFTP               = "sftp"
   211  	TypeSNS                = "sns"
   212  	TypeSQL                = "sql"
   213  	TypeSQS                = "sqs"
   214  	TypeSTDOUT             = "stdout"
   215  	TypeSubprocess         = "subprocess"
   216  	TypeSwitch             = "switch"
   217  	TypeSyncResponse       = "sync_response"
   218  	TypeTableStorage       = "table_storage"
   219  	TypeTCP                = "tcp"
   220  	TypeTry                = "try"
   221  	TypeUDP                = "udp"
   222  	TypeSocket             = "socket"
   223  	TypeWebsocket          = "websocket"
   224  	TypeZMQ4               = "zmq4"
   225  )
   226  
   227  //------------------------------------------------------------------------------
   228  
   229  // Config is the all encompassing configuration struct for all output types.
   230  // Deprecated: Do not add new components here. Instead, use the public plugin
   231  // APIs. Examples can be found in: ./internal/impl
   232  type Config struct {
   233  	Label              string                         `json:"label" yaml:"label"`
   234  	Type               string                         `json:"type" yaml:"type"`
   235  	AMQP               writer.AMQPConfig              `json:"amqp" yaml:"amqp"`
   236  	AMQP09             writer.AMQPConfig              `json:"amqp_0_9" yaml:"amqp_0_9"`
   237  	AMQP1              writer.AMQP1Config             `json:"amqp_1" yaml:"amqp_1"`
   238  	AWSDynamoDB        writer.DynamoDBConfig          `json:"aws_dynamodb" yaml:"aws_dynamodb"`
   239  	AWSKinesis         writer.KinesisConfig           `json:"aws_kinesis" yaml:"aws_kinesis"`
   240  	AWSKinesisFirehose writer.KinesisFirehoseConfig   `json:"aws_kinesis_firehose" yaml:"aws_kinesis_firehose"`
   241  	AWSS3              writer.AmazonS3Config          `json:"aws_s3" yaml:"aws_s3"`
   242  	AWSSNS             writer.SNSConfig               `json:"aws_sns" yaml:"aws_sns"`
   243  	AWSSQS             writer.AmazonSQSConfig         `json:"aws_sqs" yaml:"aws_sqs"`
   244  	AzureBlobStorage   writer.AzureBlobStorageConfig  `json:"azure_blob_storage" yaml:"azure_blob_storage"`
   245  	AzureQueueStorage  writer.AzureQueueStorageConfig `json:"azure_queue_storage" yaml:"azure_queue_storage"`
   246  	AzureTableStorage  writer.AzureTableStorageConfig `json:"azure_table_storage" yaml:"azure_table_storage"`
   247  	BlobStorage        writer.AzureBlobStorageConfig  `json:"blob_storage" yaml:"blob_storage"`
   248  	Broker             BrokerConfig                   `json:"broker" yaml:"broker"`
   249  	Cache              writer.CacheConfig             `json:"cache" yaml:"cache"`
   250  	Cassandra          CassandraConfig                `json:"cassandra" yaml:"cassandra"`
   251  	Drop               writer.DropConfig              `json:"drop" yaml:"drop"`
   252  	DropOn             DropOnConfig                   `json:"drop_on" yaml:"drop_on"`
   253  	DropOnError        DropOnErrorConfig              `json:"drop_on_error" yaml:"drop_on_error"`
   254  	Dynamic            DynamicConfig                  `json:"dynamic" yaml:"dynamic"`
   255  	DynamoDB           writer.DynamoDBConfig          `json:"dynamodb" yaml:"dynamodb"`
   256  	Elasticsearch      writer.ElasticsearchConfig     `json:"elasticsearch" yaml:"elasticsearch"`
   257  	Fallback           TryConfig                      `json:"fallback" yaml:"fallback"`
   258  	File               FileConfig                     `json:"file" yaml:"file"`
   259  	Files              writer.FilesConfig             `json:"files" yaml:"files"`
   260  	GCPCloudStorage    GCPCloudStorageConfig          `json:"gcp_cloud_storage" yaml:"gcp_cloud_storage"`
   261  	GCPPubSub          writer.GCPPubSubConfig         `json:"gcp_pubsub" yaml:"gcp_pubsub"`
   262  	HDFS               writer.HDFSConfig              `json:"hdfs" yaml:"hdfs"`
   263  	HTTPClient         writer.HTTPClientConfig        `json:"http_client" yaml:"http_client"`
   264  	HTTPServer         HTTPServerConfig               `json:"http_server" yaml:"http_server"`
   265  	Inproc             InprocConfig                   `json:"inproc" yaml:"inproc"`
   266  	Kafka              writer.KafkaConfig             `json:"kafka" yaml:"kafka"`
   267  	Kinesis            writer.KinesisConfig           `json:"kinesis" yaml:"kinesis"`
   268  	KinesisFirehose    writer.KinesisFirehoseConfig   `json:"kinesis_firehose" yaml:"kinesis_firehose"`
   269  	MongoDB            MongoDBConfig                  `json:"mongodb" yaml:"mongodb"`
   270  	MQTT               writer.MQTTConfig              `json:"mqtt" yaml:"mqtt"`
   271  	Nanomsg            writer.NanomsgConfig           `json:"nanomsg" yaml:"nanomsg"`
   272  	NATS               writer.NATSConfig              `json:"nats" yaml:"nats"`
   273  	NATSJetStream      NATSJetStreamConfig            `json:"nats_jetstream" yaml:"nats_jetstream"`
   274  	NATSStream         writer.NATSStreamConfig        `json:"nats_stream" yaml:"nats_stream"`
   275  	NSQ                writer.NSQConfig               `json:"nsq" yaml:"nsq"`
   276  	Plugin             interface{}                    `json:"plugin,omitempty" yaml:"plugin,omitempty"`
   277  	Pulsar             PulsarConfig                   `json:"pulsar" yaml:"pulsar"`
   278  	RedisHash          writer.RedisHashConfig         `json:"redis_hash" yaml:"redis_hash"`
   279  	RedisList          writer.RedisListConfig         `json:"redis_list" yaml:"redis_list"`
   280  	RedisPubSub        writer.RedisPubSubConfig       `json:"redis_pubsub" yaml:"redis_pubsub"`
   281  	RedisStreams       writer.RedisStreamsConfig      `json:"redis_streams" yaml:"redis_streams"`
   282  	Reject             RejectConfig                   `json:"reject" yaml:"reject"`
   283  	Resource           string                         `json:"resource" yaml:"resource"`
   284  	Retry              RetryConfig                    `json:"retry" yaml:"retry"`
   285  	S3                 writer.AmazonS3Config          `json:"s3" yaml:"s3"`
   286  	SFTP               SFTPConfig                     `json:"sftp" yaml:"sftp"`
   287  	SNS                writer.SNSConfig               `json:"sns" yaml:"sns"`
   288  	SQL                SQLConfig                      `json:"sql" yaml:"sql"`
   289  	SQS                writer.AmazonSQSConfig         `json:"sqs" yaml:"sqs"`
   290  	STDOUT             STDOUTConfig                   `json:"stdout" yaml:"stdout"`
   291  	Subprocess         SubprocessConfig               `json:"subprocess" yaml:"subprocess"`
   292  	Switch             SwitchConfig                   `json:"switch" yaml:"switch"`
   293  	SyncResponse       struct{}                       `json:"sync_response" yaml:"sync_response"`
   294  	TableStorage       writer.AzureTableStorageConfig `json:"table_storage" yaml:"table_storage"`
   295  	TCP                writer.TCPConfig               `json:"tcp" yaml:"tcp"`
   296  	Try                TryConfig                      `json:"try" yaml:"try"`
   297  	UDP                writer.UDPConfig               `json:"udp" yaml:"udp"`
   298  	Socket             writer.SocketConfig            `json:"socket" yaml:"socket"`
   299  	Websocket          writer.WebsocketConfig         `json:"websocket" yaml:"websocket"`
   300  	ZMQ4               *writer.ZMQ4Config             `json:"zmq4,omitempty" yaml:"zmq4,omitempty"`
   301  	Processors         []processor.Config             `json:"processors" yaml:"processors"`
   302  }
   303  
   304  // NewConfig returns a configuration struct fully populated with default values.
   305  // Deprecated: Do not add new components here. Instead, use the public plugin
   306  // APIs. Examples can be found in: ./internal/impl
   307  func NewConfig() Config {
   308  	return Config{
   309  		Label:              "",
   310  		Type:               "stdout",
   311  		AMQP:               writer.NewAMQPConfig(),
   312  		AMQP09:             writer.NewAMQPConfig(),
   313  		AMQP1:              writer.NewAMQP1Config(),
   314  		AWSDynamoDB:        writer.NewDynamoDBConfig(),
   315  		AWSKinesis:         writer.NewKinesisConfig(),
   316  		AWSKinesisFirehose: writer.NewKinesisFirehoseConfig(),
   317  		AWSS3:              writer.NewAmazonS3Config(),
   318  		AWSSNS:             writer.NewSNSConfig(),
   319  		AWSSQS:             writer.NewAmazonSQSConfig(),
   320  		AzureBlobStorage:   writer.NewAzureBlobStorageConfig(),
   321  		AzureQueueStorage:  writer.NewAzureQueueStorageConfig(),
   322  		AzureTableStorage:  writer.NewAzureTableStorageConfig(),
   323  		BlobStorage:        writer.NewAzureBlobStorageConfig(),
   324  		Broker:             NewBrokerConfig(),
   325  		Cache:              writer.NewCacheConfig(),
   326  		Cassandra:          NewCassandraConfig(),
   327  		Drop:               writer.NewDropConfig(),
   328  		DropOn:             NewDropOnConfig(),
   329  		DropOnError:        NewDropOnErrorConfig(),
   330  		Dynamic:            NewDynamicConfig(),
   331  		DynamoDB:           writer.NewDynamoDBConfig(),
   332  		Elasticsearch:      writer.NewElasticsearchConfig(),
   333  		Fallback:           NewTryConfig(),
   334  		File:               NewFileConfig(),
   335  		Files:              writer.NewFilesConfig(),
   336  		GCPCloudStorage:    NewGCPCloudStorageConfig(),
   337  		GCPPubSub:          writer.NewGCPPubSubConfig(),
   338  		HDFS:               writer.NewHDFSConfig(),
   339  		HTTPClient:         writer.NewHTTPClientConfig(),
   340  		HTTPServer:         NewHTTPServerConfig(),
   341  		Inproc:             NewInprocConfig(),
   342  		Kafka:              writer.NewKafkaConfig(),
   343  		Kinesis:            writer.NewKinesisConfig(),
   344  		KinesisFirehose:    writer.NewKinesisFirehoseConfig(),
   345  		MQTT:               writer.NewMQTTConfig(),
   346  		MongoDB:            NewMongoDBConfig(),
   347  		Nanomsg:            writer.NewNanomsgConfig(),
   348  		NATS:               writer.NewNATSConfig(),
   349  		NATSJetStream:      NewNATSJetStreamConfig(),
   350  		NATSStream:         writer.NewNATSStreamConfig(),
   351  		NSQ:                writer.NewNSQConfig(),
   352  		Plugin:             nil,
   353  		Pulsar:             NewPulsarConfig(),
   354  		RedisHash:          writer.NewRedisHashConfig(),
   355  		RedisList:          writer.NewRedisListConfig(),
   356  		RedisPubSub:        writer.NewRedisPubSubConfig(),
   357  		RedisStreams:       writer.NewRedisStreamsConfig(),
   358  		Reject:             NewRejectConfig(),
   359  		Resource:           "",
   360  		Retry:              NewRetryConfig(),
   361  		S3:                 writer.NewAmazonS3Config(),
   362  		SFTP:               NewSFTPConfig(),
   363  		SNS:                writer.NewSNSConfig(),
   364  		SQL:                NewSQLConfig(),
   365  		SQS:                writer.NewAmazonSQSConfig(),
   366  		STDOUT:             NewSTDOUTConfig(),
   367  		Subprocess:         NewSubprocessConfig(),
   368  		Switch:             NewSwitchConfig(),
   369  		SyncResponse:       struct{}{},
   370  		TableStorage:       writer.NewAzureTableStorageConfig(),
   371  		TCP:                writer.NewTCPConfig(),
   372  		Try:                NewTryConfig(),
   373  		UDP:                writer.NewUDPConfig(),
   374  		Socket:             writer.NewSocketConfig(),
   375  		Websocket:          writer.NewWebsocketConfig(),
   376  		ZMQ4:               writer.NewZMQ4Config(),
   377  		Processors:         []processor.Config{},
   378  	}
   379  }
   380  
   381  //------------------------------------------------------------------------------
   382  
   383  // SanitiseConfig returns a sanitised version of the Config, meaning sections
   384  // that aren't relevant to behaviour are removed.
   385  func SanitiseConfig(conf Config) (interface{}, error) {
   386  	return conf.Sanitised(false)
   387  }
   388  
   389  // Sanitised returns a sanitised version of the config, meaning sections that
   390  // aren't relevant to behaviour are removed. Also optionally removes deprecated
   391  // fields.
   392  func (conf Config) Sanitised(removeDeprecated bool) (interface{}, error) {
   393  	outputMap, err := config.SanitizeComponent(conf)
   394  	if err != nil {
   395  		return nil, err
   396  	}
   397  	if spec, exists := pluginSpecs[conf.Type]; exists {
   398  		if spec.confSanitiser != nil {
   399  			outputMap["plugin"] = spec.confSanitiser(conf.Plugin)
   400  		}
   401  	}
   402  	if err := docs.SanitiseComponentConfig(
   403  		docs.TypeOutput,
   404  		map[string]interface{}(outputMap),
   405  		docs.ShouldDropDeprecated(removeDeprecated),
   406  	); err != nil {
   407  		return nil, err
   408  	}
   409  	return outputMap, nil
   410  }
   411  
   412  //------------------------------------------------------------------------------
   413  
   414  // UnmarshalYAML ensures that when parsing configs that are in a map or slice
   415  // the default values are still applied.
   416  func (conf *Config) UnmarshalYAML(value *yaml.Node) error {
   417  	type confAlias Config
   418  	aliased := confAlias(NewConfig())
   419  
   420  	err := value.Decode(&aliased)
   421  	if err != nil {
   422  		return fmt.Errorf("line %v: %v", value.Line, err)
   423  	}
   424  
   425  	var spec docs.ComponentSpec
   426  	if aliased.Type, spec, err = docs.GetInferenceCandidateFromYAML(nil, docs.TypeOutput, aliased.Type, value); err != nil {
   427  		return fmt.Errorf("line %v: %w", value.Line, err)
   428  	}
   429  
   430  	if spec.Plugin {
   431  		pluginNode, err := docs.GetPluginConfigYAML(aliased.Type, value)
   432  		if err != nil {
   433  			return fmt.Errorf("line %v: %v", value.Line, err)
   434  		}
   435  		if spec, exists := pluginSpecs[aliased.Type]; exists && spec.confConstructor != nil {
   436  			conf := spec.confConstructor()
   437  			if err = pluginNode.Decode(conf); err != nil {
   438  				return fmt.Errorf("line %v: %v", value.Line, err)
   439  			}
   440  			aliased.Plugin = conf
   441  		} else {
   442  			aliased.Plugin = &pluginNode
   443  		}
   444  	} else {
   445  		aliased.Plugin = nil
   446  	}
   447  
   448  	*conf = Config(aliased)
   449  	return nil
   450  }
   451  
   452  //------------------------------------------------------------------------------
   453  
   454  // New creates an output type based on an output configuration.
   455  func New(
   456  	conf Config,
   457  	mgr types.Manager,
   458  	log log.Modular,
   459  	stats metrics.Type,
   460  	pipelines ...types.PipelineConstructorFunc,
   461  ) (Type, error) {
   462  	if mgrV2, ok := mgr.(interface {
   463  		NewOutput(Config, ...types.PipelineConstructorFunc) (types.Output, error)
   464  	}); ok {
   465  		return mgrV2.NewOutput(conf, pipelines...)
   466  	}
   467  	if c, ok := Constructors[conf.Type]; ok {
   468  		return c.constructor(conf, mgr, log, stats, pipelines...)
   469  	}
   470  	if c, ok := pluginSpecs[conf.Type]; ok {
   471  		return c.constructor(conf, mgr, log, stats, pipelines...)
   472  	}
   473  	return nil, types.ErrInvalidOutputType
   474  }
   475  
   476  //------------------------------------------------------------------------------