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 //------------------------------------------------------------------------------