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

     1  package tracer
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"sort"
     8  	"strings"
     9  
    10  	"github.com/Jeffail/benthos/v3/internal/docs"
    11  	"github.com/Jeffail/benthos/v3/lib/util/config"
    12  	yaml "gopkg.in/yaml.v3"
    13  )
    14  
    15  //------------------------------------------------------------------------------
    16  
    17  // Errors for the tracer package.
    18  var (
    19  	ErrInvalidTracerType = errors.New("invalid tracer type")
    20  )
    21  
    22  //------------------------------------------------------------------------------
    23  
    24  // TypeSpec is a constructor and a usage description for each tracer type.
    25  type TypeSpec struct {
    26  	constructor func(conf Config, opts ...func(Type)) (Type, error)
    27  
    28  	Status      docs.Status
    29  	Version     string
    30  	Summary     string
    31  	Description string
    32  	Footnotes   string
    33  	config      docs.FieldSpec
    34  	FieldSpecs  docs.FieldSpecs
    35  }
    36  
    37  // ConstructorFunc is a func signature able to construct a tracer.
    38  type ConstructorFunc func(Config, ...func(Type)) (Type, error)
    39  
    40  // WalkConstructors iterates each component constructor.
    41  func WalkConstructors(fn func(ConstructorFunc, docs.ComponentSpec)) {
    42  	inferred := docs.ComponentFieldsFromConf(NewConfig())
    43  	for k, v := range Constructors {
    44  		conf := v.config
    45  		if len(v.FieldSpecs) > 0 {
    46  			conf = docs.FieldComponent().WithChildren(v.FieldSpecs.DefaultAndTypeFrom(inferred[k])...)
    47  		} else {
    48  			conf.Children = conf.Children.DefaultAndTypeFrom(inferred[k])
    49  		}
    50  		spec := docs.ComponentSpec{
    51  			Type:        docs.TypeTracer,
    52  			Name:        k,
    53  			Summary:     v.Summary,
    54  			Description: v.Description,
    55  			Footnotes:   v.Footnotes,
    56  			Config:      conf,
    57  			Status:      v.Status,
    58  			Version:     v.Version,
    59  		}
    60  		fn(ConstructorFunc(v.constructor), spec)
    61  	}
    62  }
    63  
    64  // Constructors is a map of all tracer types with their specs.
    65  var Constructors = map[string]TypeSpec{}
    66  
    67  //------------------------------------------------------------------------------
    68  
    69  // String constants representing each tracer type.
    70  const (
    71  	TypeJaeger = "jaeger"
    72  	TypeNone   = "none"
    73  )
    74  
    75  //------------------------------------------------------------------------------
    76  
    77  // Type is an interface implemented by all tracer types.
    78  type Type interface {
    79  	// Close stops and cleans up the tracers resources.
    80  	Close() error
    81  }
    82  
    83  //------------------------------------------------------------------------------
    84  
    85  // Config is the all encompassing configuration struct for all tracer types.
    86  type Config struct {
    87  	Type   string       `json:"type" yaml:"type"`
    88  	Jaeger JaegerConfig `json:"jaeger" yaml:"jaeger"`
    89  	None   struct{}     `json:"none" yaml:"none"`
    90  }
    91  
    92  // NewConfig returns a configuration struct fully populated with default values.
    93  func NewConfig() Config {
    94  	return Config{
    95  		Type:   TypeNone,
    96  		Jaeger: NewJaegerConfig(),
    97  		None:   struct{}{},
    98  	}
    99  }
   100  
   101  // SanitiseConfig returns a sanitised version of the Config, meaning sections
   102  // that aren't relevant to behaviour are removed.
   103  func SanitiseConfig(conf Config) (interface{}, error) {
   104  	return conf.Sanitised(false)
   105  }
   106  
   107  // Sanitised returns a sanitised version of the config, meaning sections that
   108  // aren't relevant to behaviour are removed. Also optionally removes deprecated
   109  // fields.
   110  func (conf Config) Sanitised(removeDeprecated bool) (interface{}, error) {
   111  	outputMap, err := config.SanitizeComponent(conf)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	if err := docs.SanitiseComponentConfig(
   116  		docs.TypeTracer,
   117  		map[string]interface{}(outputMap),
   118  		docs.ShouldDropDeprecated(removeDeprecated),
   119  	); err != nil {
   120  		return nil, err
   121  	}
   122  	return outputMap, nil
   123  }
   124  
   125  //------------------------------------------------------------------------------
   126  
   127  // UnmarshalYAML ensures that when parsing configs that are in a map or slice
   128  // the default values are still applied.
   129  func (conf *Config) UnmarshalYAML(value *yaml.Node) error {
   130  	type confAlias Config
   131  	aliased := confAlias(NewConfig())
   132  
   133  	err := value.Decode(&aliased)
   134  	if err != nil {
   135  		return fmt.Errorf("line %v: %v", value.Line, err)
   136  	}
   137  
   138  	if aliased.Type, _, err = docs.GetInferenceCandidateFromYAML(nil, docs.TypeTracer, aliased.Type, value); err != nil {
   139  		return fmt.Errorf("line %v: %w", value.Line, err)
   140  	}
   141  
   142  	*conf = Config(aliased)
   143  	return nil
   144  }
   145  
   146  //------------------------------------------------------------------------------
   147  
   148  var header = "This document was generated with `benthos --list-tracers`" + `
   149  
   150  A tracer type represents a destination for Benthos to send tracing events to
   151  such as [Jaeger](https://www.jaegertracing.io/).
   152  
   153  When a tracer is configured all messages will be allocated a root span during
   154  ingestion that represents their journey through a Benthos pipeline. Many Benthos
   155  processors create spans, and so tracing is a great way to analyse the pathways
   156  of individual messages as they progress through a Benthos instance.
   157  
   158  Some inputs, such as ` + "`http_server` and `http_client`" + `, are capable of
   159  extracting a root span from the source of the message (HTTP headers). This is
   160  a work in progress and should eventually expand so that all inputs have a way of
   161  doing so.
   162  
   163  A tracer config section looks like this:
   164  
   165  ` + "``` yaml" + `
   166  tracer:
   167    jaeger:
   168      agent_address: localhost:6831
   169      sampler_param: 1
   170      sampler_type: const
   171      service_name: benthos
   172  ` + "```" + `
   173  
   174  WARNING: Although the configuration spec of this component is stable the format
   175  of spans, tags and logs created by Benthos is subject to change as it is tuned
   176  for improvement.`
   177  
   178  // Descriptions returns a formatted string of collated descriptions of each
   179  // type.
   180  func Descriptions() string {
   181  	// Order our types alphabetically
   182  	names := []string{}
   183  	for name := range Constructors {
   184  		names = append(names, name)
   185  	}
   186  	sort.Strings(names)
   187  
   188  	buf := bytes.Buffer{}
   189  	buf.WriteString("Tracer Types\n")
   190  	buf.WriteString(strings.Repeat("=", 12))
   191  	buf.WriteString("\n\n")
   192  	buf.WriteString(header)
   193  	buf.WriteString("\n\n")
   194  
   195  	// Append each description
   196  	for i, name := range names {
   197  		var confBytes []byte
   198  
   199  		conf := NewConfig()
   200  		conf.Type = name
   201  		if confSanit, err := SanitiseConfig(conf); err == nil {
   202  			confBytes, _ = config.MarshalYAML(confSanit)
   203  		}
   204  
   205  		buf.WriteString("## ")
   206  		buf.WriteString("`" + name + "`")
   207  		buf.WriteString("\n")
   208  		if confBytes != nil {
   209  			buf.WriteString("\n``` yaml\n")
   210  			buf.Write(confBytes)
   211  			buf.WriteString("```\n")
   212  		}
   213  		buf.WriteString(Constructors[name].Description)
   214  		buf.WriteString("\n")
   215  		if i != (len(names) - 1) {
   216  			buf.WriteString("\n---\n")
   217  		}
   218  	}
   219  	return buf.String()
   220  }
   221  
   222  // New creates a tracer type based on a configuration.
   223  func New(conf Config, opts ...func(Type)) (Type, error) {
   224  	if c, ok := Constructors[conf.Type]; ok {
   225  		return c.constructor(conf, opts...)
   226  	}
   227  	return nil, ErrInvalidTracerType
   228  }
   229  
   230  //------------------------------------------------------------------------------