promote formatLabels to mapper package

Signed-off-by: Wangchong Zhou <fffonion@gmail.com>
This commit is contained in:
Wangchong Zhou 2018-09-28 13:13:06 -07:00
parent 5262b2904c
commit fcf11f02e5
No known key found for this signature in database
GPG key ID: B607274584E8D5E5
3 changed files with 45 additions and 49 deletions

View file

@ -24,17 +24,17 @@ var (
templateReplaceCaptureRE = regexp.MustCompile(`\$\{?([a-zA-Z0-9_\$]+)\}?`) templateReplaceCaptureRE = regexp.MustCompile(`\$\{?([a-zA-Z0-9_\$]+)\}?`)
) )
type templateFormatter struct { type TemplateFormatter struct {
captureIndexes []int captureIndexes []int
captureCount int captureCount int
fmtString string fmtString string
} }
func newTemplateFormatter(valueExpr string, captureCount int) *templateFormatter { func NewTemplateFormatter(valueExpr string, captureCount int) *TemplateFormatter {
matches := templateReplaceCaptureRE.FindAllStringSubmatch(valueExpr, -1) matches := templateReplaceCaptureRE.FindAllStringSubmatch(valueExpr, -1)
if len(matches) == 0 { if len(matches) == 0 {
// if no regex reference found, keep it as it is // 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 var indexes []int
@ -51,14 +51,14 @@ func newTemplateFormatter(valueExpr string, captureCount int) *templateFormatter
indexes = append(indexes, idx-1) indexes = append(indexes, idx-1)
} }
} }
return &templateFormatter{ return &TemplateFormatter{
captureIndexes: indexes, captureIndexes: indexes,
captureCount: len(indexes), captureCount: len(indexes),
fmtString: valueFormatter, fmtString: valueFormatter,
} }
} }
func (formatter *templateFormatter) format(captures map[int]string) string { func (formatter *TemplateFormatter) Format(captures []string) string {
if formatter.captureCount == 0 { if formatter.captureCount == 0 {
// no label substitution, keep as it is // no label substitution, keep as it is
return formatter.fmtString return formatter.fmtString

View file

@ -17,7 +17,6 @@ import (
"regexp" "regexp"
"strings" "strings"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/log" "github.com/prometheus/common/log"
) )
@ -26,10 +25,8 @@ type mappingState struct {
minRemainingLength int minRemainingLength int
maxRemainingLength int maxRemainingLength int
// result* members are nil unless there's a metric ends with this state // result* members are nil unless there's a metric ends with this state
result interface{} Result interface{}
resultPriority int ResultPriority int
resultNameFormatter *templateFormatter
resultLabelsFormatter map[string]*templateFormatter
} }
type fsmBacktrackStackCursor struct { type fsmBacktrackStackCursor struct {
@ -69,8 +66,7 @@ func NewFSM(metricTypes []string, maxPossibleTransitions int, orderingDisabled b
} }
// AddState adds a state into the existing FSM // AddState adds a state into the existing FSM
func (f *FSM) AddState(match string, name string, labels prometheus.Labels, matchMetricType string, func (f *FSM) AddState(match string, name string, matchMetricType string, maxPossibleTransitions int, result interface{}) int {
maxPossibleTransitions int, result interface{}) {
// first split by "." // first split by "."
matchFields := strings.Split(match, ".") matchFields := strings.Split(match, ".")
// fill into our FSM // fill into our FSM
@ -97,7 +93,7 @@ func (f *FSM) AddState(match string, name string, labels prometheus.Labels, matc
root.transitions[field] = state root.transitions[field] = state
// if this is last field, set result to currentMapping instance // if this is last field, set result to currentMapping instance
if i == len(matchFields)-1 { if i == len(matchFields)-1 {
root.transitions[field].result = result root.transitions[field].Result = result
} }
} else { } else {
(*state).maxRemainingLength = max(len(matchFields)-i-1, (*state).maxRemainingLength) (*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) 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 { for _, state := range finalStates {
state.resultNameFormatter = nameFmt state.ResultPriority = f.statesCount
state.resultLabelsFormatter = currentLabelFormatter
state.resultPriority = f.statesCount
} }
f.statesCount++ f.statesCount++
return captureCount
} }
// GetMapping implements a mapping algorithm for Glob pattern // 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, ".") matchFields := strings.Split(statsdMetric, ".")
currentState := f.root.transitions[statsdMetricType] currentState := f.root.transitions[statsdMetricType]
@ -142,7 +130,7 @@ func (f *FSM) GetMapping(statsdMetric string, statsdMetricType string) (interfac
// the return variable // the return variable
var finalState *mappingState 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 // keep track of captured group so we don't need to do append() on captures
captureIdx := 0 captureIdx := 0
filedsCount := len(matchFields) filedsCount := len(matchFields)
@ -191,11 +179,11 @@ func (f *FSM) GetMapping(statsdMetric string, statsdMetricType string) (interfac
} // backtrack will resume from here } // backtrack will resume from here
// do we reach a final state? // do we reach a final state?
if state.result != nil && i == filedsCount-1 { if state.Result != nil && i == filedsCount-1 {
if f.OrderingDisabled { if f.OrderingDisabled {
finalState = state finalState = state
return formatLabels(finalState, captures) return finalState, captures
} else if finalState == nil || finalState.resultPriority > state.resultPriority { } else if finalState == nil || finalState.ResultPriority > state.ResultPriority {
// if we care about ordering, try to find a result with highest prioity // if we care about ordering, try to find a result with highest prioity
finalState = state 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 // TestIfNeedBacktracking test if backtrack is needed for current mappings
@ -323,17 +311,3 @@ func TestIfNeedBacktracking(mappings []string, orderingDisabled bool) bool {
return !orderingDisabled || backtrackingNeeded 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
}

View file

@ -57,8 +57,11 @@ type matchMetricType string
type MetricMapping struct { type MetricMapping struct {
Match string `yaml:"match"` Match string `yaml:"match"`
Name string `yaml:"name"` Name string `yaml:"name"`
nameFormatter *fsm.TemplateFormatter
regex *regexp.Regexp regex *regexp.Regexp
Labels prometheus.Labels `yaml:"labels"` Labels prometheus.Labels `yaml:"labels"`
labelKeys []string
labelFormatters []*fsm.TemplateFormatter
TimerType TimerType `yaml:"timer_type"` TimerType TimerType `yaml:"timer_type"`
Buckets []float64 `yaml:"buckets"` Buckets []float64 `yaml:"buckets"`
Quantiles []metricObjective `yaml:"quantiles"` Quantiles []metricObjective `yaml:"quantiles"`
@ -137,9 +140,22 @@ func (m *MetricMapper) InitFromYAMLString(fileContents string) error {
return fmt.Errorf("invalid match: %s", currentMapping.Match) 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) 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 { } else {
if regex, err := regexp.Compile(currentMapping.Match); err != nil { if regex, err := regexp.Compile(currentMapping.Match); err != nil {
return fmt.Errorf("invalid regex %s in mapping: %v", currentMapping.Match, err) 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) { func (m *MetricMapper) GetMapping(statsdMetric string, statsdMetricType MetricType) (*MetricMapping, prometheus.Labels, bool) {
// glob matching // glob matching
if m.doFSM { if m.doFSM {
mapping, mappingName, labels, matched := m.FSM.GetMapping(statsdMetric, string(statsdMetricType)) finalState, captures := m.FSM.GetMapping(statsdMetric, string(statsdMetricType))
if matched { if finalState != nil && finalState.Result != nil {
mapping.(*MetricMapping).Name = mappingName result := finalState.Result.(*MetricMapping)
return mapping.(*MetricMapping), labels, matched result.Name = result.nameFormatter.Format(captures)
} else if !matched && !m.doRegex {
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 // if there's no regex match type, return immediately
return nil, nil, false return nil, nil, false
} }