From fcf11f02e5c881c4d6d53820892942f0b8f5b820 Mon Sep 17 00:00:00 2001 From: Wangchong Zhou Date: Fri, 28 Sep 2018 13:13:06 -0700 Subject: [PATCH] promote formatLabels to mapper package Signed-off-by: Wangchong Zhou --- pkg/mapper/fsm/formatter.go | 10 ++++---- pkg/mapper/fsm/fsm.go | 50 +++++++++---------------------------- pkg/mapper/mapper.go | 34 ++++++++++++++++++++----- 3 files changed, 45 insertions(+), 49 deletions(-) diff --git a/pkg/mapper/fsm/formatter.go b/pkg/mapper/fsm/formatter.go index 362c220..6acd91b 100644 --- a/pkg/mapper/fsm/formatter.go +++ b/pkg/mapper/fsm/formatter.go @@ -24,17 +24,17 @@ var ( templateReplaceCaptureRE = regexp.MustCompile(`\$\{?([a-zA-Z0-9_\$]+)\}?`) ) -type templateFormatter struct { +type TemplateFormatter struct { captureIndexes []int captureCount int fmtString string } -func newTemplateFormatter(valueExpr string, captureCount int) *templateFormatter { +func NewTemplateFormatter(valueExpr string, captureCount int) *TemplateFormatter { matches := templateReplaceCaptureRE.FindAllStringSubmatch(valueExpr, -1) if len(matches) == 0 { // if no regex reference found, keep it as it is - return &templateFormatter{captureCount: 0, fmtString: valueExpr} + return &TemplateFormatter{captureCount: 0, fmtString: valueExpr} } var indexes []int @@ -51,14 +51,14 @@ func newTemplateFormatter(valueExpr string, captureCount int) *templateFormatter indexes = append(indexes, idx-1) } } - return &templateFormatter{ + return &TemplateFormatter{ captureIndexes: indexes, captureCount: len(indexes), fmtString: valueFormatter, } } -func (formatter *templateFormatter) format(captures map[int]string) string { +func (formatter *TemplateFormatter) Format(captures []string) string { if formatter.captureCount == 0 { // no label substitution, keep as it is return formatter.fmtString diff --git a/pkg/mapper/fsm/fsm.go b/pkg/mapper/fsm/fsm.go index 0d7dd7f..8e764a9 100644 --- a/pkg/mapper/fsm/fsm.go +++ b/pkg/mapper/fsm/fsm.go @@ -17,7 +17,6 @@ import ( "regexp" "strings" - "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/log" ) @@ -26,10 +25,8 @@ type mappingState struct { minRemainingLength int maxRemainingLength int // result* members are nil unless there's a metric ends with this state - result interface{} - resultPriority int - resultNameFormatter *templateFormatter - resultLabelsFormatter map[string]*templateFormatter + Result interface{} + ResultPriority int } type fsmBacktrackStackCursor struct { @@ -69,8 +66,7 @@ func NewFSM(metricTypes []string, maxPossibleTransitions int, orderingDisabled b } // AddState adds a state into the existing FSM -func (f *FSM) AddState(match string, name string, labels prometheus.Labels, matchMetricType string, - maxPossibleTransitions int, result interface{}) { +func (f *FSM) AddState(match string, name string, matchMetricType string, maxPossibleTransitions int, result interface{}) int { // first split by "." matchFields := strings.Split(match, ".") // fill into our FSM @@ -97,7 +93,7 @@ func (f *FSM) AddState(match string, name string, labels prometheus.Labels, matc root.transitions[field] = state // if this is last field, set result to currentMapping instance if i == len(matchFields)-1 { - root.transitions[field].result = result + root.transitions[field].Result = result } } else { (*state).maxRemainingLength = max(len(matchFields)-i-1, (*state).maxRemainingLength) @@ -112,26 +108,18 @@ func (f *FSM) AddState(match string, name string, labels prometheus.Labels, matc } finalStates = append(finalStates, root) } - nameFmt := newTemplateFormatter(name, captureCount) - - currentLabelFormatter := make(map[string]*templateFormatter, captureCount) - for label, valueExpr := range labels { - lblFmt := newTemplateFormatter(valueExpr, captureCount) - currentLabelFormatter[label] = lblFmt - } for _, state := range finalStates { - state.resultNameFormatter = nameFmt - state.resultLabelsFormatter = currentLabelFormatter - state.resultPriority = f.statesCount + state.ResultPriority = f.statesCount } f.statesCount++ + return captureCount } // GetMapping implements a mapping algorithm for Glob pattern -func (f *FSM) GetMapping(statsdMetric string, statsdMetricType string) (interface{}, string, prometheus.Labels, bool) { +func (f *FSM) GetMapping(statsdMetric string, statsdMetricType string) (*mappingState, []string) { matchFields := strings.Split(statsdMetric, ".") currentState := f.root.transitions[statsdMetricType] @@ -142,7 +130,7 @@ func (f *FSM) GetMapping(statsdMetric string, statsdMetricType string) (interfac // the return variable var finalState *mappingState - captures := make(map[int]string, len(matchFields)) + captures := make([]string, len(matchFields)) // keep track of captured group so we don't need to do append() on captures captureIdx := 0 filedsCount := len(matchFields) @@ -191,11 +179,11 @@ func (f *FSM) GetMapping(statsdMetric string, statsdMetricType string) (interfac } // backtrack will resume from here // do we reach a final state? - if state.result != nil && i == filedsCount-1 { + if state.Result != nil && i == filedsCount-1 { if f.OrderingDisabled { finalState = state - return formatLabels(finalState, captures) - } else if finalState == nil || finalState.resultPriority > state.resultPriority { + return finalState, captures + } else if finalState == nil || finalState.ResultPriority > state.ResultPriority { // if we care about ordering, try to find a result with highest prioity finalState = state } @@ -230,7 +218,7 @@ func (f *FSM) GetMapping(statsdMetric string, statsdMetricType string) (interfac } } - return formatLabels(finalState, captures) + return finalState, captures } // TestIfNeedBacktracking test if backtrack is needed for current mappings @@ -323,17 +311,3 @@ func TestIfNeedBacktracking(mappings []string, orderingDisabled bool) bool { return !orderingDisabled || backtrackingNeeded } - -func formatLabels(finalState *mappingState, captures map[int]string) (interface{}, string, prometheus.Labels, bool) { - // format name and labels - if finalState != nil { - name := finalState.resultNameFormatter.format(captures) - - labels := prometheus.Labels{} - for key, formatter := range finalState.resultLabelsFormatter { - labels[key] = formatter.format(captures) - } - return finalState.result, name, labels, true - } - return nil, "", nil, false -} diff --git a/pkg/mapper/mapper.go b/pkg/mapper/mapper.go index e853aba..dc5a735 100644 --- a/pkg/mapper/mapper.go +++ b/pkg/mapper/mapper.go @@ -57,8 +57,11 @@ type matchMetricType string type MetricMapping struct { Match string `yaml:"match"` Name string `yaml:"name"` + nameFormatter *fsm.TemplateFormatter regex *regexp.Regexp Labels prometheus.Labels `yaml:"labels"` + labelKeys []string + labelFormatters []*fsm.TemplateFormatter TimerType TimerType `yaml:"timer_type"` Buckets []float64 `yaml:"buckets"` Quantiles []metricObjective `yaml:"quantiles"` @@ -137,9 +140,22 @@ func (m *MetricMapper) InitFromYAMLString(fileContents string) error { return fmt.Errorf("invalid match: %s", currentMapping.Match) } - n.FSM.AddState(currentMapping.Match, currentMapping.Name, currentMapping.Labels, string(currentMapping.MatchMetricType), + captureCount := n.FSM.AddState(currentMapping.Match, currentMapping.Name, string(currentMapping.MatchMetricType), remainingMappingsCount, currentMapping) + currentMapping.nameFormatter = fsm.NewTemplateFormatter(currentMapping.Name, captureCount) + + labelKeys := make([]string, len(currentMapping.Labels)) + labelFormatters := make([]*fsm.TemplateFormatter, len(currentMapping.Labels)) + labelIndex := 0 + for label, valueExpr := range currentMapping.Labels { + labelKeys[labelIndex] = label + labelFormatters[labelIndex] = fsm.NewTemplateFormatter(valueExpr, captureCount) + labelIndex++ + } + currentMapping.labelFormatters = labelFormatters + currentMapping.labelKeys = labelKeys + } else { if regex, err := regexp.Compile(currentMapping.Match); err != nil { return fmt.Errorf("invalid regex %s in mapping: %v", currentMapping.Match, err) @@ -200,11 +216,17 @@ func (m *MetricMapper) InitFromFile(fileName string) error { func (m *MetricMapper) GetMapping(statsdMetric string, statsdMetricType MetricType) (*MetricMapping, prometheus.Labels, bool) { // glob matching if m.doFSM { - mapping, mappingName, labels, matched := m.FSM.GetMapping(statsdMetric, string(statsdMetricType)) - if matched { - mapping.(*MetricMapping).Name = mappingName - return mapping.(*MetricMapping), labels, matched - } else if !matched && !m.doRegex { + finalState, captures := m.FSM.GetMapping(statsdMetric, string(statsdMetricType)) + if finalState != nil && finalState.Result != nil { + result := finalState.Result.(*MetricMapping) + result.Name = result.nameFormatter.Format(captures) + + labels := prometheus.Labels{} + for index, formatter := range result.labelFormatters { + labels[result.labelKeys[index]] = formatter.Format(captures) + } + return result, labels, true + } else if !m.doRegex { // if there's no regex match type, return immediately return nil, nil, false }