github.com/Jeffail/benthos/v3@v3.65.0/lib/input/plugin.go (about)

     1  package input
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"sort"
     7  	"strings"
     8  
     9  	"github.com/Jeffail/benthos/v3/internal/interop/plugins"
    10  	"github.com/Jeffail/benthos/v3/lib/log"
    11  	"github.com/Jeffail/benthos/v3/lib/metrics"
    12  	"github.com/Jeffail/benthos/v3/lib/types"
    13  	"github.com/Jeffail/benthos/v3/lib/util/config"
    14  )
    15  
    16  //------------------------------------------------------------------------------
    17  
    18  // PluginConstructor is a func that constructs a Benthos input plugin. These are
    19  // plugins that are specific to certain use cases, experimental, private or
    20  // otherwise unfit for widespread general use. Any number of plugins can be
    21  // specified when using Benthos as a framework.
    22  //
    23  // The configuration object will be the result of the PluginConfigConstructor
    24  // after overlaying the user configuration.
    25  type PluginConstructor func(
    26  	config interface{},
    27  	manager types.Manager,
    28  	logger log.Modular,
    29  	metrics metrics.Type,
    30  ) (types.Input, error)
    31  
    32  // PluginConfigConstructor is a func that returns a pointer to a new and fully
    33  // populated configuration struct for a plugin type.
    34  type PluginConfigConstructor func() interface{}
    35  
    36  // PluginConfigSanitiser is a function that takes a configuration object for a
    37  // plugin and returns a sanitised (minimal) version of it for printing in
    38  // examples and plugin documentation.
    39  //
    40  // This function is useful for when a plugins configuration struct is very large
    41  // and complex, but can sometimes be expressed in a more concise way without
    42  // losing the original intent.
    43  type PluginConfigSanitiser func(conf interface{}) interface{}
    44  
    45  type pluginSpec struct {
    46  	constructor     ConstructorFunc
    47  	confConstructor PluginConfigConstructor
    48  	confSanitiser   PluginConfigSanitiser
    49  	description     string
    50  }
    51  
    52  // pluginSpecs is a map of all input plugin type specs.
    53  var pluginSpecs = map[string]pluginSpec{}
    54  
    55  // GetDeprecatedPlugin returns a constructor for an old plugin if it exists.
    56  func GetDeprecatedPlugin(name string) (ConstructorFunc, bool) {
    57  	spec, ok := pluginSpecs[name]
    58  	if !ok {
    59  		return nil, false
    60  	}
    61  	return spec.constructor, true
    62  }
    63  
    64  // RegisterPlugin registers a plugin by a unique name so that it can be
    65  // constructed similar to regular inputs. If configuration is not needed for
    66  // this plugin then configConstructor can be nil. A constructor for the plugin
    67  // itself must be provided.
    68  func RegisterPlugin(
    69  	typeString string,
    70  	configConstructor PluginConfigConstructor,
    71  	constructor PluginConstructor,
    72  ) {
    73  	spec := pluginSpecs[typeString]
    74  	spec.constructor = fromSimpleConstructor(func(
    75  		conf Config,
    76  		mgr types.Manager,
    77  		log log.Modular,
    78  		stats metrics.Type,
    79  	) (Type, error) {
    80  		return constructor(conf.Plugin, mgr, log, stats)
    81  	})
    82  	spec.confConstructor = configConstructor
    83  	pluginSpecs[typeString] = spec
    84  	plugins.Add(typeString, "input")
    85  }
    86  
    87  // DocumentPlugin adds a description and an optional configuration sanitiser
    88  // function to the definition of a registered plugin. This improves the
    89  // documentation generated by PluginDescriptions.
    90  func DocumentPlugin(
    91  	typeString, description string,
    92  	configSanitiser PluginConfigSanitiser,
    93  ) {
    94  	spec := pluginSpecs[typeString]
    95  	spec.description = description
    96  	spec.confSanitiser = configSanitiser
    97  	pluginSpecs[typeString] = spec
    98  }
    99  
   100  // PluginCount returns the number of registered plugins. This does NOT count the
   101  // standard set of components.
   102  func PluginCount() int {
   103  	return len(pluginSpecs)
   104  }
   105  
   106  //------------------------------------------------------------------------------
   107  
   108  var pluginHeader = "This document was generated with `benthos --list-input-plugins`." + `
   109  
   110  This document lists any input plugins that this flavour of Benthos offers beyond
   111  the standard set.`
   112  
   113  // PluginDescriptions generates and returns a markdown formatted document
   114  // listing each registered plugin and an example configuration for it.
   115  func PluginDescriptions() string {
   116  	// Order alphabetically
   117  	names := []string{}
   118  	for name := range pluginSpecs {
   119  		names = append(names, name)
   120  	}
   121  	sort.Strings(names)
   122  
   123  	buf := bytes.Buffer{}
   124  	buf.WriteString("Input Plugins\n")
   125  	buf.WriteString(strings.Repeat("=", 13))
   126  	buf.WriteString("\n\n")
   127  	buf.WriteString(pluginHeader)
   128  	buf.WriteString("\n\n")
   129  
   130  	buf.WriteString("### Contents\n\n")
   131  	for i, name := range names {
   132  		buf.WriteString(fmt.Sprintf("%v. [`%v`](#%v)\n", i+1, name, name))
   133  	}
   134  
   135  	if len(names) == 0 {
   136  		buf.WriteString("There are no plugins loaded.")
   137  	} else {
   138  		buf.WriteString("\n")
   139  	}
   140  
   141  	// Append each description
   142  	for i, name := range names {
   143  		var confBytes []byte
   144  
   145  		if confCtor := pluginSpecs[name].confConstructor; confCtor != nil {
   146  			conf := NewConfig()
   147  			conf.Type = name
   148  			conf.Plugin = confCtor()
   149  			if confSanit, err := SanitiseConfig(conf); err == nil {
   150  				confBytes, _ = config.MarshalYAML(confSanit)
   151  			}
   152  		}
   153  
   154  		buf.WriteString("## ")
   155  		buf.WriteString("`" + name + "`")
   156  		buf.WriteString("\n")
   157  		if confBytes != nil {
   158  			buf.WriteString("\n``` yaml\n")
   159  			buf.Write(confBytes)
   160  			buf.WriteString("```\n")
   161  		}
   162  		if desc := pluginSpecs[name].description; len(desc) > 0 {
   163  			buf.WriteString("\n")
   164  			buf.WriteString(desc)
   165  			buf.WriteString("\n")
   166  		}
   167  		if i != (len(names) - 1) {
   168  			buf.WriteString("\n")
   169  		}
   170  	}
   171  	return buf.String()
   172  }
   173  
   174  //------------------------------------------------------------------------------