github.com/influxdata/telegraf@v1.30.3/internal/templating/engine.go (about)

     1  package templating
     2  
     3  import (
     4  	"sort"
     5  	"strings"
     6  )
     7  
     8  const (
     9  	// DefaultSeparator is the default separation character to use when separating template parts.
    10  	DefaultSeparator = "."
    11  )
    12  
    13  // Engine uses a Matcher to retrieve the appropriate template and applies the template
    14  // to the input string
    15  type Engine struct {
    16  	joiner  string
    17  	matcher *matcher
    18  }
    19  
    20  // Apply extracts the template fields from the given line and returns the measurement
    21  // name, tags and field name
    22  //
    23  //nolint:revive //function-result-limit conditionally 4 return results allowed
    24  func (e *Engine) Apply(line string) (measurementName string, tags map[string]string, field string, err error) {
    25  	return e.matcher.match(line).Apply(line, e.joiner)
    26  }
    27  
    28  // NewEngine creates a new templating engine
    29  func NewEngine(joiner string, defaultTemplate *Template, templates []string) (*Engine, error) {
    30  	engine := Engine{
    31  		joiner:  joiner,
    32  		matcher: newMatcher(defaultTemplate),
    33  	}
    34  	templateSpecs := parseTemplateSpecs(templates)
    35  
    36  	for _, templateSpec := range templateSpecs {
    37  		if err := engine.matcher.addSpec(templateSpec); err != nil {
    38  			return nil, err
    39  		}
    40  	}
    41  
    42  	return &engine, nil
    43  }
    44  
    45  func parseTemplateSpecs(templates []string) templateSpecs {
    46  	tmplts := templateSpecs{}
    47  	for _, pattern := range templates {
    48  		tmplt := templateSpec{
    49  			separator: DefaultSeparator,
    50  		}
    51  
    52  		// Format is [separator] [filter] <template> [tag1=value1,tag2=value2]
    53  		parts := strings.Fields(pattern)
    54  		partsLength := len(parts)
    55  		if partsLength < 1 {
    56  			// ignore
    57  			continue
    58  		}
    59  		if partsLength == 1 {
    60  			tmplt.template = pattern
    61  		} else if partsLength == 4 {
    62  			tmplt.separator = parts[0]
    63  			tmplt.filter = parts[1]
    64  			tmplt.template = parts[2]
    65  			tmplt.tagstring = parts[3]
    66  		} else {
    67  			hasTagstring := strings.Contains(parts[partsLength-1], "=")
    68  			if hasTagstring {
    69  				tmplt.tagstring = parts[partsLength-1]
    70  				tmplt.template = parts[partsLength-2]
    71  				if partsLength == 3 {
    72  					tmplt.filter = parts[0]
    73  				}
    74  			} else {
    75  				tmplt.template = parts[partsLength-1]
    76  				if partsLength == 2 {
    77  					tmplt.filter = parts[0]
    78  				} else { // length == 3
    79  					tmplt.separator = parts[0]
    80  					tmplt.filter = parts[1]
    81  				}
    82  			}
    83  		}
    84  		tmplts = append(tmplts, tmplt)
    85  	}
    86  	sort.Sort(tmplts)
    87  	return tmplts
    88  }