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_\$]+)\}?`)
)
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

View file

@ -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
}

View file

@ -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
}