forked from mirrors/statsd_exporter
promote formatLabels to mapper package
Signed-off-by: Wangchong Zhou <fffonion@gmail.com>
This commit is contained in:
parent
5262b2904c
commit
fcf11f02e5
3 changed files with 45 additions and 49 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue