mirror of
https://github.com/prometheus/statsd_exporter.git
synced 2024-11-29 18:50:59 +00:00
tidy up and use go benchmark
Signed-off-by: Wangchong Zhou <fffonion@gmail.com>
This commit is contained in:
parent
6d709d52c1
commit
5262b2904c
6 changed files with 793 additions and 517 deletions
4
main.go
4
main.go
|
@ -142,7 +142,7 @@ func main() {
|
||||||
statsdListenTCP = kingpin.Flag("statsd.listen-tcp", "The TCP address on which to receive statsd metric lines. \"\" disables it.").Default(":9125").String()
|
statsdListenTCP = kingpin.Flag("statsd.listen-tcp", "The TCP address on which to receive statsd metric lines. \"\" disables it.").Default(":9125").String()
|
||||||
mappingConfig = kingpin.Flag("statsd.mapping-config", "Metric mapping configuration file name.").String()
|
mappingConfig = kingpin.Flag("statsd.mapping-config", "Metric mapping configuration file name.").String()
|
||||||
readBuffer = kingpin.Flag("statsd.read-buffer", "Size (in bytes) of the operating system's transmit read buffer associated with the UDP connection. Please make sure the kernel parameters net.core.rmem_max is set to a value greater than the value specified.").Int()
|
readBuffer = kingpin.Flag("statsd.read-buffer", "Size (in bytes) of the operating system's transmit read buffer associated with the UDP connection. Please make sure the kernel parameters net.core.rmem_max is set to a value greater than the value specified.").Int()
|
||||||
dumpFSMPath = kingpin.Flag("statsd.dump-fsm", "The path to dump internal FSM generated for glob matching as Dot file.").Default("").String()
|
dumpFSMPath = kingpin.Flag("debug.dump-fsm", "The path to dump internal FSM generated for glob matching as Dot file.").Default("").String()
|
||||||
)
|
)
|
||||||
|
|
||||||
log.AddFlags(kingpin.CommandLine)
|
log.AddFlags(kingpin.CommandLine)
|
||||||
|
@ -203,7 +203,7 @@ func main() {
|
||||||
if *dumpFSMPath != "" {
|
if *dumpFSMPath != "" {
|
||||||
err := dumpFSM(mapper, *dumpFSMPath)
|
err := dumpFSM(mapper, *dumpFSMPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error dumpping FSM:", err)
|
log.Fatal("Error dumping FSM:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
go watchConfig(*mappingConfig, mapper)
|
go watchConfig(*mappingConfig, mapper)
|
||||||
|
|
48
pkg/mapper/fsm/dump.go
Normal file
48
pkg/mapper/fsm/dump.go
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright 2018 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package fsm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DumpFSM accepts a io.writer and write the current FSM into dot file format
|
||||||
|
func (f *FSM) DumpFSM(w io.Writer) {
|
||||||
|
idx := 0
|
||||||
|
states := make(map[int]*mappingState)
|
||||||
|
states[idx] = f.root
|
||||||
|
|
||||||
|
w.Write([]byte("digraph g {\n"))
|
||||||
|
w.Write([]byte("rankdir=LR\n")) // make it vertical
|
||||||
|
w.Write([]byte("node [ label=\"\",style=filled,fillcolor=white,shape=circle ]\n")) // remove label of node
|
||||||
|
|
||||||
|
for idx < len(states) {
|
||||||
|
for field, transition := range states[idx].transitions {
|
||||||
|
states[len(states)] = transition
|
||||||
|
w.Write([]byte(fmt.Sprintf("%d -> %d [label = \"%s\"];\n", idx, len(states)-1, field)))
|
||||||
|
if idx == 0 {
|
||||||
|
// color for metric types
|
||||||
|
w.Write([]byte(fmt.Sprintf("%d [color=\"#D6B656\",fillcolor=\"#FFF2CC\"];\n", len(states)-1)))
|
||||||
|
} else if transition.transitions == nil || len(transition.transitions) == 0 {
|
||||||
|
// color for end state
|
||||||
|
w.Write([]byte(fmt.Sprintf("%d [color=\"#82B366\",fillcolor=\"#D5E8D4\"];\n", len(states)-1)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
// color for start state
|
||||||
|
w.Write([]byte(fmt.Sprintf("0 [color=\"#a94442\",fillcolor=\"#f2dede\"];\n")))
|
||||||
|
w.Write([]byte("}"))
|
||||||
|
}
|
|
@ -15,10 +15,15 @@ package fsm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
templateReplaceCaptureRE = regexp.MustCompile(`\$\{?([a-zA-Z0-9_\$]+)\}?`)
|
||||||
|
)
|
||||||
|
|
||||||
type templateFormatter struct {
|
type templateFormatter struct {
|
||||||
captureIndexes []int
|
captureIndexes []int
|
||||||
captureCount int
|
captureCount int
|
||||||
|
@ -57,7 +62,7 @@ func (formatter *templateFormatter) format(captures map[int]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
|
||||||
} else {
|
}
|
||||||
indexes := formatter.captureIndexes
|
indexes := formatter.captureIndexes
|
||||||
vargs := make([]interface{}, formatter.captureCount)
|
vargs := make([]interface{}, formatter.captureCount)
|
||||||
for i, idx := range indexes {
|
for i, idx := range indexes {
|
||||||
|
@ -65,4 +70,3 @@ func (formatter *templateFormatter) format(captures map[int]string) string {
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(formatter.fmtString, vargs...)
|
return fmt.Sprintf(formatter.fmtString, vargs...)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -14,8 +14,6 @@
|
||||||
package fsm
|
package fsm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -23,10 +21,6 @@ import (
|
||||||
"github.com/prometheus/common/log"
|
"github.com/prometheus/common/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
templateReplaceCaptureRE = regexp.MustCompile(`\$\{?([a-zA-Z0-9_\$]+)\}?`)
|
|
||||||
)
|
|
||||||
|
|
||||||
type mappingState struct {
|
type mappingState struct {
|
||||||
transitions map[string]*mappingState
|
transitions map[string]*mappingState
|
||||||
minRemainingLength int
|
minRemainingLength int
|
||||||
|
@ -49,17 +43,17 @@ type fsmBacktrackStackCursor struct {
|
||||||
|
|
||||||
type FSM struct {
|
type FSM struct {
|
||||||
root *mappingState
|
root *mappingState
|
||||||
needsBacktracking bool
|
|
||||||
metricTypes []string
|
metricTypes []string
|
||||||
disableOrdering bool
|
|
||||||
statesCount int
|
statesCount int
|
||||||
|
BacktrackingNeeded bool
|
||||||
|
OrderingDisabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFSM creates a new FSM instance
|
// NewFSM creates a new FSM instance
|
||||||
func NewFSM(metricTypes []string, maxPossibleTransitions int, disableOrdering bool) *FSM {
|
func NewFSM(metricTypes []string, maxPossibleTransitions int, orderingDisabled bool) *FSM {
|
||||||
fsm := FSM{}
|
fsm := FSM{}
|
||||||
root := &mappingState{}
|
root := &mappingState{}
|
||||||
root.transitions = make(map[string]*mappingState, 3)
|
root.transitions = make(map[string]*mappingState, len(metricTypes))
|
||||||
|
|
||||||
metricTypes = append(metricTypes, "")
|
metricTypes = append(metricTypes, "")
|
||||||
for _, field := range metricTypes {
|
for _, field := range metricTypes {
|
||||||
|
@ -67,7 +61,7 @@ func NewFSM(metricTypes []string, maxPossibleTransitions int, disableOrdering bo
|
||||||
(*state).transitions = make(map[string]*mappingState, maxPossibleTransitions)
|
(*state).transitions = make(map[string]*mappingState, maxPossibleTransitions)
|
||||||
root.transitions[string(field)] = state
|
root.transitions[string(field)] = state
|
||||||
}
|
}
|
||||||
fsm.disableOrdering = disableOrdering
|
fsm.OrderingDisabled = orderingDisabled
|
||||||
fsm.metricTypes = metricTypes
|
fsm.metricTypes = metricTypes
|
||||||
fsm.statesCount = 0
|
fsm.statesCount = 0
|
||||||
fsm.root = root
|
fsm.root = root
|
||||||
|
@ -136,38 +130,112 @@ func (f *FSM) AddState(match string, name string, labels prometheus.Labels, matc
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DumpFSM accepts a io.writer and write the current FSM into dot file format
|
// GetMapping implements a mapping algorithm for Glob pattern
|
||||||
func (f *FSM) DumpFSM(w io.Writer) {
|
func (f *FSM) GetMapping(statsdMetric string, statsdMetricType string) (interface{}, string, prometheus.Labels, bool) {
|
||||||
idx := 0
|
matchFields := strings.Split(statsdMetric, ".")
|
||||||
states := make(map[int]*mappingState)
|
currentState := f.root.transitions[statsdMetricType]
|
||||||
states[idx] = f.root
|
|
||||||
|
|
||||||
w.Write([]byte("digraph g {\n"))
|
// the cursor/pointer in the backtrack stack implemented as a double-linked list
|
||||||
w.Write([]byte("rankdir=LR\n")) // make it vertical
|
var backtrackCursor *fsmBacktrackStackCursor
|
||||||
w.Write([]byte("node [ label=\"\",style=filled,fillcolor=white,shape=circle ]\n")) // remove label of node
|
resumeFromBacktrack := false
|
||||||
|
|
||||||
for idx < len(states) {
|
// the return variable
|
||||||
for field, transition := range states[idx].transitions {
|
var finalState *mappingState
|
||||||
states[len(states)] = transition
|
|
||||||
w.Write([]byte(fmt.Sprintf("%d -> %d [label = \"%s\"];\n", idx, len(states)-1, field)))
|
captures := make(map[int]string, len(matchFields))
|
||||||
if idx == 0 {
|
// keep track of captured group so we don't need to do append() on captures
|
||||||
// color for metric types
|
captureIdx := 0
|
||||||
w.Write([]byte(fmt.Sprintf("%d [color=\"#D6B656\",fillcolor=\"#FFF2CC\"];\n", len(states)-1)))
|
filedsCount := len(matchFields)
|
||||||
} else if transition.transitions == nil || len(transition.transitions) == 0 {
|
i := 0
|
||||||
// color for end state
|
var state *mappingState
|
||||||
w.Write([]byte(fmt.Sprintf("%d [color=\"#82B366\",fillcolor=\"#D5E8D4\"];\n", len(states)-1)))
|
for { // the loop for backtracking
|
||||||
|
for { // the loop for a single "depth only" search
|
||||||
|
var present bool
|
||||||
|
// if we resume from backtrack, we should skip this branch in this case
|
||||||
|
// since the state that were saved at the end of this branch
|
||||||
|
if !resumeFromBacktrack {
|
||||||
|
if len(currentState.transitions) > 0 {
|
||||||
|
field := matchFields[i]
|
||||||
|
state, present = currentState.transitions[field]
|
||||||
|
fieldsLeft := filedsCount - i - 1
|
||||||
|
// also compare length upfront to avoid unnecessary loop or backtrack
|
||||||
|
if !present || fieldsLeft > state.maxRemainingLength || fieldsLeft < state.minRemainingLength {
|
||||||
|
state, present = currentState.transitions["*"]
|
||||||
|
if !present || fieldsLeft > state.maxRemainingLength || fieldsLeft < state.minRemainingLength {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
captures[captureIdx] = field
|
||||||
|
captureIdx++
|
||||||
|
}
|
||||||
|
} else if f.BacktrackingNeeded {
|
||||||
|
// if backtracking is needed, also check for alternative transition
|
||||||
|
altState, present := currentState.transitions["*"]
|
||||||
|
if !present || fieldsLeft > altState.maxRemainingLength || fieldsLeft < altState.minRemainingLength {
|
||||||
|
} else {
|
||||||
|
// push to backtracking stack
|
||||||
|
newCursor := fsmBacktrackStackCursor{prev: backtrackCursor, state: altState,
|
||||||
|
fieldIndex: i,
|
||||||
|
captureIndex: captureIdx, currentCapture: field,
|
||||||
|
}
|
||||||
|
// if this is not the first time, connect to the previous cursor
|
||||||
|
if backtrackCursor != nil {
|
||||||
|
backtrackCursor.next = &newCursor
|
||||||
|
}
|
||||||
|
backtrackCursor = &newCursor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
idx++
|
} else {
|
||||||
|
// no more transitions for this state
|
||||||
|
break
|
||||||
}
|
}
|
||||||
// color for start state
|
} // backtrack will resume from here
|
||||||
w.Write([]byte(fmt.Sprintf("0 [color=\"#a94442\",fillcolor=\"#f2dede\"];\n")))
|
|
||||||
w.Write([]byte("}"))
|
// do we reach a final state?
|
||||||
|
if state.result != nil && i == filedsCount-1 {
|
||||||
|
if f.OrderingDisabled {
|
||||||
|
finalState = state
|
||||||
|
return formatLabels(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
|
||||||
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestIfNeedBacktracking test if backtrack is needed for current FSM
|
i++
|
||||||
func (f *FSM) TestIfNeedBacktracking(mappings []string) bool {
|
if i >= filedsCount {
|
||||||
needBacktrack := false
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
resumeFromBacktrack = false
|
||||||
|
currentState = state
|
||||||
|
}
|
||||||
|
if backtrackCursor == nil {
|
||||||
|
// if we are not doing backtracking or all path has been travesaled
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
// pop one from stack
|
||||||
|
state = backtrackCursor.state
|
||||||
|
currentState = state
|
||||||
|
i = backtrackCursor.fieldIndex
|
||||||
|
captureIdx = backtrackCursor.captureIndex + 1
|
||||||
|
// put the * capture back
|
||||||
|
captures[captureIdx-1] = backtrackCursor.currentCapture
|
||||||
|
backtrackCursor = backtrackCursor.prev
|
||||||
|
if backtrackCursor != nil {
|
||||||
|
// deref for GC
|
||||||
|
backtrackCursor.next = nil
|
||||||
|
}
|
||||||
|
resumeFromBacktrack = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatLabels(finalState, captures)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestIfNeedBacktracking test if backtrack is needed for current mappings
|
||||||
|
func TestIfNeedBacktracking(mappings []string, orderingDisabled bool) bool {
|
||||||
|
backtrackingNeeded := false
|
||||||
// A has * in rules there's other transisitions at the same state
|
// A has * in rules there's other transisitions at the same state
|
||||||
// this makes A the cause of backtracking
|
// this makes A the cause of backtracking
|
||||||
ruleByLength := make(map[int][]string)
|
ruleByLength := make(map[int][]string)
|
||||||
|
@ -221,9 +289,9 @@ func (f *FSM) TestIfNeedBacktracking(mappings []string) bool {
|
||||||
for i2, r2 := range rules {
|
for i2, r2 := range rules {
|
||||||
if i2 != i1 && len(re1.FindStringSubmatchIndex(r2)) > 0 {
|
if i2 != i1 && len(re1.FindStringSubmatchIndex(r2)) > 0 {
|
||||||
// log if we care about ordering and the superset occurs before
|
// log if we care about ordering and the superset occurs before
|
||||||
if !f.disableOrdering && i1 < i2 {
|
if !orderingDisabled && i1 < i2 {
|
||||||
log.Warnf("match \"%s\" is a super set of match \"%s\" but in a lower order, "+
|
log.Warnf("match \"%s\" is a super set of match \"%s\" but in a lower order, "+
|
||||||
"the first will never be matched\n", r1, r2)
|
"the first will never be matched", r1, r2)
|
||||||
}
|
}
|
||||||
currentRuleNeedBacktrack = false
|
currentRuleNeedBacktrack = false
|
||||||
}
|
}
|
||||||
|
@ -242,8 +310,8 @@ func (f *FSM) TestIfNeedBacktracking(mappings []string) bool {
|
||||||
|
|
||||||
if currentRuleNeedBacktrack {
|
if currentRuleNeedBacktrack {
|
||||||
log.Warnf("backtracking required because of match \"%s\", "+
|
log.Warnf("backtracking required because of match \"%s\", "+
|
||||||
"matching performance may be degraded\n", r1)
|
"matching performance may be degraded", r1)
|
||||||
needBacktrack = true
|
backtrackingNeeded = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,112 +320,8 @@ func (f *FSM) TestIfNeedBacktracking(mappings []string) bool {
|
||||||
// since transistions are stored in (unordered) map
|
// since transistions are stored in (unordered) map
|
||||||
// note: don't move this branch to the beginning of this function
|
// note: don't move this branch to the beginning of this function
|
||||||
// since we need logs for superset rules
|
// since we need logs for superset rules
|
||||||
f.needsBacktracking = !f.disableOrdering || needBacktrack
|
|
||||||
|
|
||||||
return f.needsBacktracking
|
return !orderingDisabled || backtrackingNeeded
|
||||||
}
|
|
||||||
|
|
||||||
// GetMapping implements a mapping algorithm for Glob pattern
|
|
||||||
func (f *FSM) GetMapping(statsdMetric string, statsdMetricType string) (interface{}, string, prometheus.Labels, bool) {
|
|
||||||
matchFields := strings.Split(statsdMetric, ".")
|
|
||||||
currentState := f.root.transitions[statsdMetricType]
|
|
||||||
|
|
||||||
// the cursor/pointer in the backtrack stack implemented as a double-linked list
|
|
||||||
var backtrackCursor *fsmBacktrackStackCursor
|
|
||||||
resumeFromBacktrack := false
|
|
||||||
|
|
||||||
// the return variable
|
|
||||||
var finalState *mappingState
|
|
||||||
|
|
||||||
captures := make(map[int]string, len(matchFields))
|
|
||||||
// keep track of captured group so we don't need to do append() on captures
|
|
||||||
captureIdx := 0
|
|
||||||
filedsCount := len(matchFields)
|
|
||||||
i := 0
|
|
||||||
var state *mappingState
|
|
||||||
for { // the loop for backtracking
|
|
||||||
for { // the loop for a single "depth only" search
|
|
||||||
var present bool
|
|
||||||
// if we resume from backtrack, we should skip this branch in this case
|
|
||||||
// since the state that were saved at the end of this branch
|
|
||||||
if !resumeFromBacktrack {
|
|
||||||
if len(currentState.transitions) > 0 {
|
|
||||||
field := matchFields[i]
|
|
||||||
state, present = currentState.transitions[field]
|
|
||||||
fieldsLeft := filedsCount - i - 1
|
|
||||||
// also compare length upfront to avoid unnecessary loop or backtrack
|
|
||||||
if !present || fieldsLeft > state.maxRemainingLength || fieldsLeft < state.minRemainingLength {
|
|
||||||
state, present = currentState.transitions["*"]
|
|
||||||
if !present || fieldsLeft > state.maxRemainingLength || fieldsLeft < state.minRemainingLength {
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
captures[captureIdx] = field
|
|
||||||
captureIdx++
|
|
||||||
}
|
|
||||||
} else if f.needsBacktracking {
|
|
||||||
// if backtracking is needed, also check for alternative transition
|
|
||||||
altState, present := currentState.transitions["*"]
|
|
||||||
if !present || fieldsLeft > altState.maxRemainingLength || fieldsLeft < altState.minRemainingLength {
|
|
||||||
} else {
|
|
||||||
// push to backtracking stack
|
|
||||||
newCursor := fsmBacktrackStackCursor{prev: backtrackCursor, state: altState,
|
|
||||||
fieldIndex: i,
|
|
||||||
captureIndex: captureIdx, currentCapture: field,
|
|
||||||
}
|
|
||||||
// if this is not the first time, connect to the previous cursor
|
|
||||||
if backtrackCursor != nil {
|
|
||||||
backtrackCursor.next = &newCursor
|
|
||||||
}
|
|
||||||
backtrackCursor = &newCursor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// no more transitions for this state
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} // backtrack will resume from here
|
|
||||||
|
|
||||||
// do we reach a final state?
|
|
||||||
if state.result != nil && i == filedsCount-1 {
|
|
||||||
if f.disableOrdering {
|
|
||||||
finalState = state
|
|
||||||
return formatLabels(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
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
i++
|
|
||||||
if i >= filedsCount {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
resumeFromBacktrack = false
|
|
||||||
currentState = state
|
|
||||||
}
|
|
||||||
if backtrackCursor == nil {
|
|
||||||
// if we are not doing backtracking or all path has been travesaled
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
// pop one from stack
|
|
||||||
state = backtrackCursor.state
|
|
||||||
currentState = state
|
|
||||||
i = backtrackCursor.fieldIndex
|
|
||||||
captureIdx = backtrackCursor.captureIndex + 1
|
|
||||||
// put the * capture back
|
|
||||||
captures[captureIdx-1] = backtrackCursor.currentCapture
|
|
||||||
backtrackCursor = backtrackCursor.prev
|
|
||||||
if backtrackCursor != nil {
|
|
||||||
// deref for GC
|
|
||||||
backtrackCursor.next = nil
|
|
||||||
}
|
|
||||||
resumeFromBacktrack = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return formatLabels(finalState, captures)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatLabels(finalState *mappingState, captures map[int]string) (interface{}, string, prometheus.Labels, bool) {
|
func formatLabels(finalState *mappingState, captures map[int]string) (interface{}, string, prometheus.Labels, bool) {
|
||||||
|
|
|
@ -31,8 +31,6 @@ var (
|
||||||
metricLineRE = regexp.MustCompile(`^(\*\.|` + statsdMetricRE + `\.)+(\*|` + statsdMetricRE + `)$`)
|
metricLineRE = regexp.MustCompile(`^(\*\.|` + statsdMetricRE + `\.)+(\*|` + statsdMetricRE + `)$`)
|
||||||
metricNameRE = regexp.MustCompile(`^([a-zA-Z_]|` + templateReplaceRE + `)([a-zA-Z0-9_]|` + templateReplaceRE + `)*$`)
|
metricNameRE = regexp.MustCompile(`^([a-zA-Z_]|` + templateReplaceRE + `)([a-zA-Z0-9_]|` + templateReplaceRE + `)*$`)
|
||||||
labelNameRE = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]+$`)
|
labelNameRE = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]+$`)
|
||||||
|
|
||||||
templateReplaceCaptureRE = regexp.MustCompile(`\$\{?([a-zA-Z0-9_\$]+)\}?`)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type mapperConfigDefaults struct {
|
type mapperConfigDefaults struct {
|
||||||
|
@ -81,20 +79,6 @@ var defaultQuantiles = []metricObjective{
|
||||||
{Quantile: 0.99, Error: 0.001},
|
{Quantile: 0.99, Error: 0.001},
|
||||||
}
|
}
|
||||||
|
|
||||||
func min(x, y int) int {
|
|
||||||
if x < y {
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
return y
|
|
||||||
}
|
|
||||||
|
|
||||||
func max(x, y int) int {
|
|
||||||
if x > y {
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
return y
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MetricMapper) InitFromYAMLString(fileContents string) error {
|
func (m *MetricMapper) InitFromYAMLString(fileContents string) error {
|
||||||
var n MetricMapper
|
var n MetricMapper
|
||||||
|
|
||||||
|
@ -191,7 +175,7 @@ func (m *MetricMapper) InitFromYAMLString(fileContents string) error {
|
||||||
mappings = append(mappings, mapping.Match)
|
mappings = append(mappings, mapping.Match)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n.FSM.TestIfNeedBacktracking(mappings)
|
n.FSM.BacktrackingNeeded = fsm.TestIfNeedBacktracking(mappings, n.FSM.OrderingDisabled)
|
||||||
|
|
||||||
m.FSM = n.FSM
|
m.FSM = n.FSM
|
||||||
m.doRegex = n.doRegex
|
m.doRegex = n.doRegex
|
||||||
|
|
|
@ -16,7 +16,6 @@ package mapper
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type mappings map[string]struct {
|
type mappings map[string]struct {
|
||||||
|
@ -26,6 +25,35 @@ type mappings map[string]struct {
|
||||||
notPresent bool
|
notPresent bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ruleTemplateSingleMatchGlob = `
|
||||||
|
- match: metric%d.*
|
||||||
|
name: "metric_single"
|
||||||
|
labels:
|
||||||
|
name: "$1"
|
||||||
|
`
|
||||||
|
ruleTemplateSingleMatchRegex = `
|
||||||
|
- match: metric%d\.([^.]*)
|
||||||
|
name: "metric_single"
|
||||||
|
labels:
|
||||||
|
name: "$1"
|
||||||
|
`
|
||||||
|
|
||||||
|
ruleTemplateMultipleMatchGlob = `
|
||||||
|
- match: metric%d.*.*.*.*.*.*.*.*.*.*.*.*
|
||||||
|
name: "metric_multi"
|
||||||
|
labels:
|
||||||
|
name: "$1-$2-$3.$4-$5-$6.$7-$8-$9.$10-$11-$12"
|
||||||
|
`
|
||||||
|
|
||||||
|
ruleTemplateMultipleMatchRegex = `
|
||||||
|
- match: metric%d\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)
|
||||||
|
name: "metric_multi"
|
||||||
|
labels:
|
||||||
|
name: "$1-$2-$3.$4-$5-$6.$7-$8-$9.$10-$11-$12"
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
func TestMetricMapperYAML(t *testing.T) {
|
func TestMetricMapperYAML(t *testing.T) {
|
||||||
scenarios := []struct {
|
scenarios := []struct {
|
||||||
config string
|
config string
|
||||||
|
@ -615,46 +643,8 @@ func duplicateRules(count int, template string) string {
|
||||||
}
|
}
|
||||||
return rules
|
return rules
|
||||||
}
|
}
|
||||||
|
func BenchmarkGlob(b *testing.B) {
|
||||||
func TestPerformance(t *testing.T) {
|
config := `---
|
||||||
sampleRulesAmount := 100
|
|
||||||
|
|
||||||
ruleTemplateSingleMatchGlob := `
|
|
||||||
- match: metric%d.*
|
|
||||||
name: "metric_single"
|
|
||||||
labels:
|
|
||||||
name: "$1"
|
|
||||||
`
|
|
||||||
ruleTemplateSingleMatchRegex := `
|
|
||||||
- match: metric%d\.([^.]*)
|
|
||||||
name: "metric_single"
|
|
||||||
labels:
|
|
||||||
name: "$1"
|
|
||||||
`
|
|
||||||
|
|
||||||
ruleTemplateMultipleMatchGlob := `
|
|
||||||
- match: metric%d.*.*.*.*.*.*.*.*.*.*.*.*
|
|
||||||
name: "metric_multi"
|
|
||||||
labels:
|
|
||||||
name: "$1-$2-$3.$4-$5-$6.$7-$8-$9.$10-$11-$12"
|
|
||||||
`
|
|
||||||
|
|
||||||
ruleTemplateMultipleMatchRegex := `
|
|
||||||
- match: metric%d\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)
|
|
||||||
name: "metric_multi"
|
|
||||||
labels:
|
|
||||||
name: "$1-$2-$3.$4-$5-$6.$7-$8-$9.$10-$11-$12"
|
|
||||||
`
|
|
||||||
|
|
||||||
scenarios := []struct {
|
|
||||||
name string
|
|
||||||
config string
|
|
||||||
configBad bool
|
|
||||||
mappings mappings
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "glob",
|
|
||||||
config: `---
|
|
||||||
mappings:
|
mappings:
|
||||||
- match: test.dispatcher.*.*.succeeded
|
- match: test.dispatcher.*.*.succeeded
|
||||||
name: "dispatch_events"
|
name: "dispatch_events"
|
||||||
|
@ -692,8 +682,8 @@ mappings:
|
||||||
second: "$2"
|
second: "$2"
|
||||||
third: "$3"
|
third: "$3"
|
||||||
job: "-"
|
job: "-"
|
||||||
`,
|
`
|
||||||
mappings: mappings{
|
mappings := mappings{
|
||||||
"test.dispatcher.FooProcessor.send.succeeded": {
|
"test.dispatcher.FooProcessor.send.succeeded": {
|
||||||
name: "ignored-in-test-dont-set-me",
|
name: "ignored-in-test-dont-set-me",
|
||||||
},
|
},
|
||||||
|
@ -707,11 +697,25 @@ mappings:
|
||||||
name: "ignored-in-test-dont-set-me",
|
name: "ignored-in-test-dont-set-me",
|
||||||
},
|
},
|
||||||
"foo.bar.baz": {},
|
"foo.bar.baz": {},
|
||||||
},
|
}
|
||||||
},
|
|
||||||
{
|
mapper := MetricMapper{}
|
||||||
name: "glob no ordering",
|
err := mapper.InitFromYAMLString(config)
|
||||||
config: `---
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkGlobNoOrdering(b *testing.B) {
|
||||||
|
config := `---
|
||||||
defaults:
|
defaults:
|
||||||
glob_disable_ordering: true
|
glob_disable_ordering: true
|
||||||
mappings:
|
mappings:
|
||||||
|
@ -751,8 +755,8 @@ mappings:
|
||||||
second: "$2"
|
second: "$2"
|
||||||
third: "$3"
|
third: "$3"
|
||||||
job: "-"
|
job: "-"
|
||||||
`,
|
`
|
||||||
mappings: mappings{
|
mappings := mappings{
|
||||||
"test.dispatcher.FooProcessor.send.succeeded": {
|
"test.dispatcher.FooProcessor.send.succeeded": {
|
||||||
name: "ignored-in-test-dont-set-me",
|
name: "ignored-in-test-dont-set-me",
|
||||||
},
|
},
|
||||||
|
@ -766,11 +770,25 @@ mappings:
|
||||||
name: "ignored-in-test-dont-set-me",
|
name: "ignored-in-test-dont-set-me",
|
||||||
},
|
},
|
||||||
"foo.bar.baz": {},
|
"foo.bar.baz": {},
|
||||||
},
|
}
|
||||||
},
|
|
||||||
{
|
mapper := MetricMapper{}
|
||||||
name: "glob with backtracking (no ordering implicated)",
|
err := mapper.InitFromYAMLString(config)
|
||||||
config: `---
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkGlobNoOrderingWithBacktracking(b *testing.B) {
|
||||||
|
config := `---
|
||||||
defaults:
|
defaults:
|
||||||
glob_disable_ordering: true
|
glob_disable_ordering: true
|
||||||
mappings:
|
mappings:
|
||||||
|
@ -817,8 +835,8 @@ mappings:
|
||||||
second: "$2"
|
second: "$2"
|
||||||
third: "$3"
|
third: "$3"
|
||||||
job: "-"
|
job: "-"
|
||||||
`,
|
`
|
||||||
mappings: mappings{
|
mappings := mappings{
|
||||||
"test.dispatcher.FooProcessor.send.succeeded": {
|
"test.dispatcher.FooProcessor.send.succeeded": {
|
||||||
name: "ignored-in-test-dont-set-me",
|
name: "ignored-in-test-dont-set-me",
|
||||||
},
|
},
|
||||||
|
@ -832,11 +850,25 @@ mappings:
|
||||||
name: "ignored-in-test-dont-set-me",
|
name: "ignored-in-test-dont-set-me",
|
||||||
},
|
},
|
||||||
"foo.bar.baz": {},
|
"foo.bar.baz": {},
|
||||||
},
|
}
|
||||||
},
|
|
||||||
{
|
mapper := MetricMapper{}
|
||||||
name: "regex",
|
err := mapper.InitFromYAMLString(config)
|
||||||
config: `---
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkRegex(b *testing.B) {
|
||||||
|
config := `---
|
||||||
defaults:
|
defaults:
|
||||||
match_type: regex
|
match_type: regex
|
||||||
mappings:
|
mappings:
|
||||||
|
@ -876,8 +908,8 @@ mappings:
|
||||||
second: "$2"
|
second: "$2"
|
||||||
third: "$3"
|
third: "$3"
|
||||||
job: "-"
|
job: "-"
|
||||||
`,
|
`
|
||||||
mappings: mappings{
|
mappings := mappings{
|
||||||
"test.dispatcher.FooProcessor.send.succeeded": {
|
"test.dispatcher.FooProcessor.send.succeeded": {
|
||||||
name: "ignored-in-test-dont-set-me",
|
name: "ignored-in-test-dont-set-me",
|
||||||
},
|
},
|
||||||
|
@ -891,252 +923,496 @@ mappings:
|
||||||
name: "ignored-in-test-dont-set-me",
|
name: "ignored-in-test-dont-set-me",
|
||||||
},
|
},
|
||||||
"foo.bar.baz": {},
|
"foo.bar.baz": {},
|
||||||
},
|
}
|
||||||
},
|
|
||||||
{},
|
mapper := MetricMapper{}
|
||||||
{
|
err := mapper.InitFromYAMLString(config)
|
||||||
name: "glob single match ",
|
if err != nil {
|
||||||
config: `---
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkGlobSingleMatch(b *testing.B) {
|
||||||
|
config := `---
|
||||||
mappings:
|
mappings:
|
||||||
- match: metric.*
|
- match: metric.*
|
||||||
name: "metric_one"
|
name: "metric_one"
|
||||||
labels:
|
labels:
|
||||||
name: "$1"
|
name: "$1"
|
||||||
`,
|
`
|
||||||
mappings: mappings{
|
mappings := mappings{
|
||||||
"metric.aaa": {},
|
"metric.aaa": {},
|
||||||
"metric.bbb": {},
|
"metric.bbb": {},
|
||||||
},
|
}
|
||||||
},
|
|
||||||
{
|
mapper := MetricMapper{}
|
||||||
name: "regex single match",
|
err := mapper.InitFromYAMLString(config)
|
||||||
config: `---
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkRegexSingleMatch(b *testing.B) {
|
||||||
|
config := `---
|
||||||
mappings:
|
mappings:
|
||||||
- match: metric\.([^.]*)
|
- match: metric\.([^.]*)
|
||||||
name: "metric_one"
|
name: "metric_one"
|
||||||
match_type: regex
|
match_type: regex
|
||||||
labels:
|
labels:
|
||||||
name: "$1"
|
name: "$1"
|
||||||
`,
|
`
|
||||||
mappings: mappings{
|
mappings := mappings{
|
||||||
"metric.aaa": {},
|
"metric.aaa": {},
|
||||||
"metric.bbb": {},
|
"metric.bbb": {},
|
||||||
},
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
name: "glob multiple captures",
|
|
||||||
config: `---
|
|
||||||
mappings:
|
|
||||||
- match: metric.*.*.*.*.*.*.*.*.*.*.*.*
|
|
||||||
name: "metric_multi"
|
|
||||||
labels:
|
|
||||||
name: "$1-$2-$3.$4-$5-$6.$7-$8-$9.$10-$11-$12"
|
|
||||||
`,
|
|
||||||
mappings: mappings{
|
|
||||||
"metric.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "regex multiple captures",
|
|
||||||
config: `---
|
|
||||||
mappings:
|
|
||||||
- match: metric\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)
|
|
||||||
name: "metric_multi"
|
|
||||||
match_type: regex
|
|
||||||
labels:
|
|
||||||
name: "$1-$2-$3.$4-$5-$6.$7-$8-$9.$10-$11-$12"
|
|
||||||
`,
|
|
||||||
mappings: mappings{
|
|
||||||
"metric.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "glob multiple captures no format",
|
|
||||||
config: `---
|
|
||||||
mappings:
|
|
||||||
- match: metric.*.*.*.*.*.*.*.*.*.*.*.*
|
|
||||||
name: "metric_multi"
|
|
||||||
labels:
|
|
||||||
name: "$1"
|
|
||||||
`,
|
|
||||||
mappings: mappings{
|
|
||||||
"metric.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "regex multiple captures no expansion",
|
|
||||||
config: `---
|
|
||||||
mappings:
|
|
||||||
- match: metric\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)
|
|
||||||
name: "metric_multi"
|
|
||||||
match_type: regex
|
|
||||||
labels:
|
|
||||||
name: "$1"
|
|
||||||
`,
|
|
||||||
mappings: mappings{
|
|
||||||
"metric.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
name: "glob multiple captures in different labels",
|
|
||||||
config: `---
|
|
||||||
mappings:
|
|
||||||
- match: metric.*.*.*.*.*.*.*.*.*.*.*.*
|
|
||||||
name: "metric_multi"
|
|
||||||
labels:
|
|
||||||
label1: "$1"
|
|
||||||
label2: "$2"
|
|
||||||
label3: "$3"
|
|
||||||
label4: "$4"
|
|
||||||
label5: "$5"
|
|
||||||
label6: "$6"
|
|
||||||
label7: "$7"
|
|
||||||
label8: "$8"
|
|
||||||
label9: "$9"
|
|
||||||
label10: "$10"
|
|
||||||
label11: "$11"
|
|
||||||
label12: "$12"
|
|
||||||
`,
|
|
||||||
mappings: mappings{
|
|
||||||
"metric.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "regex multiple captures",
|
|
||||||
config: `---
|
|
||||||
mappings:
|
|
||||||
- match: metric\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)
|
|
||||||
name: "metric_multi"
|
|
||||||
match_type: regex
|
|
||||||
labels:
|
|
||||||
label1: "$1"
|
|
||||||
label2: "$2"
|
|
||||||
label3: "$3"
|
|
||||||
label4: "$4"
|
|
||||||
label5: "$5"
|
|
||||||
label6: "$6"
|
|
||||||
label7: "$7"
|
|
||||||
label8: "$8"
|
|
||||||
label9: "$9"
|
|
||||||
label10: "$10"
|
|
||||||
label11: "$11"
|
|
||||||
label12: "$12"
|
|
||||||
`,
|
|
||||||
mappings: mappings{
|
|
||||||
"metric.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
name: "glob 100 rules",
|
|
||||||
config: `---
|
|
||||||
mappings:` + duplicateRules(sampleRulesAmount, ruleTemplateSingleMatchGlob),
|
|
||||||
mappings: mappings{
|
|
||||||
"metric100.a": {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "glob 100 rules, no match",
|
|
||||||
config: `---
|
|
||||||
mappings:` + duplicateRules(sampleRulesAmount, ruleTemplateSingleMatchGlob),
|
|
||||||
mappings: mappings{
|
|
||||||
"metricnomatchy.a": {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "glob 100 rules without ordering, no match",
|
|
||||||
config: `---
|
|
||||||
defaults:
|
|
||||||
glob_disable_ordering: true
|
|
||||||
mappings:` + duplicateRules(sampleRulesAmount, ruleTemplateSingleMatchGlob),
|
|
||||||
mappings: mappings{
|
|
||||||
"metricnomatchy.a": {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "regex 100 rules, average case",
|
|
||||||
config: `---
|
|
||||||
defaults:
|
|
||||||
match_type: regex
|
|
||||||
mappings:` + duplicateRules(sampleRulesAmount, ruleTemplateSingleMatchRegex),
|
|
||||||
mappings: mappings{
|
|
||||||
fmt.Sprintf("metric%d.a", sampleRulesAmount/2): {}, // average match position
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "regex 100 rules, worst case",
|
|
||||||
config: `---
|
|
||||||
defaults:
|
|
||||||
match_type: regex
|
|
||||||
mappings:` + duplicateRules(sampleRulesAmount, ruleTemplateSingleMatchRegex),
|
|
||||||
mappings: mappings{
|
|
||||||
"metric100.a": {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
name: "glob 100 rules, multiple captures",
|
|
||||||
config: `---
|
|
||||||
mappings:` + duplicateRules(sampleRulesAmount, ruleTemplateMultipleMatchGlob),
|
|
||||||
mappings: mappings{
|
|
||||||
"metric50.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "regex 100 rules, multiple captures, average case",
|
|
||||||
config: `---
|
|
||||||
defaults:
|
|
||||||
match_type: regex
|
|
||||||
mappings:` + duplicateRules(sampleRulesAmount, ruleTemplateMultipleMatchRegex),
|
|
||||||
mappings: mappings{
|
|
||||||
fmt.Sprintf("metric%d.a.b.c.d.e.f.g.h.i.j.k.l", sampleRulesAmount/2): {}, // average match position
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
name: "glob 10 rules",
|
|
||||||
config: `---
|
|
||||||
mappings:` + duplicateRules(sampleRulesAmount, ruleTemplateSingleMatchGlob),
|
|
||||||
mappings: mappings{
|
|
||||||
"metric50.a": {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "regex 10 rules average case",
|
|
||||||
config: `---
|
|
||||||
defaults:
|
|
||||||
match_type: regex
|
|
||||||
mappings:` + duplicateRules(sampleRulesAmount, ruleTemplateSingleMatchRegex),
|
|
||||||
mappings: mappings{
|
|
||||||
fmt.Sprintf("metric%d.a", sampleRulesAmount/2): {}, // average match position
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, scenario := range scenarios {
|
|
||||||
if len(scenario.config) == 0 {
|
|
||||||
fmt.Println("--------------------------------")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
mapper := MetricMapper{}
|
mapper := MetricMapper{}
|
||||||
err := mapper.InitFromYAMLString(scenario.config)
|
err := mapper.InitFromYAMLString(config)
|
||||||
if err != nil && !scenario.configBad {
|
if err != nil {
|
||||||
t.Fatalf("%d. Config load error: %s %s", i, scenario.config, err)
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
}
|
|
||||||
if err == nil && scenario.configBad {
|
|
||||||
t.Fatalf("%d. Expected bad config, but loaded ok: %s", i, scenario.config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var dummyMetricType MetricType = ""
|
var dummyMetricType MetricType
|
||||||
start := time.Now()
|
b.ResetTimer()
|
||||||
for j := 1; j < 10000; j++ {
|
for j := 0; j < b.N; j++ {
|
||||||
for metric, _ := range scenario.mappings {
|
for metric := range mappings {
|
||||||
mapper.GetMapping(metric, dummyMetricType)
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Printf("finished 10000 iterations for \"%s\" in %v\n", scenario.name, time.Now().Sub(start))
|
}
|
||||||
|
|
||||||
|
func BenchmarkGlobMultipleCaptures(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
mappings:
|
||||||
|
- match: metric.*.*.*.*.*.*.*.*.*.*.*.*
|
||||||
|
name: "metric_multi"
|
||||||
|
labels:
|
||||||
|
name: "$1-$2-$3.$4-$5-$6.$7-$8-$9.$10-$11-$12"
|
||||||
|
`
|
||||||
|
mappings := mappings{
|
||||||
|
"metric.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkRegexMultipleCaptures(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
mappings:
|
||||||
|
- match: metric\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)
|
||||||
|
name: "metric_multi"
|
||||||
|
match_type: regex
|
||||||
|
labels:
|
||||||
|
name: "$1-$2-$3.$4-$5-$6.$7-$8-$9.$10-$11-$12"
|
||||||
|
`
|
||||||
|
mappings := mappings{
|
||||||
|
"metric.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkGlobMultipleCapturesNoFormat(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
mappings:
|
||||||
|
- match: metric.*.*.*.*.*.*.*.*.*.*.*.*
|
||||||
|
name: "metric_multi"
|
||||||
|
labels:
|
||||||
|
name: "not_relevant"
|
||||||
|
`
|
||||||
|
mappings := mappings{
|
||||||
|
"metric.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkRegexMultipleCapturesNoFormat(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
mappings:
|
||||||
|
- match: metric\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)
|
||||||
|
name: "metric_multi"
|
||||||
|
match_type: regex
|
||||||
|
labels:
|
||||||
|
name: "not_relevant"
|
||||||
|
`
|
||||||
|
mappings := mappings{
|
||||||
|
"metric.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkGlobMultipleCapturesDifferentLabels(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
mappings:
|
||||||
|
- match: metric.*.*.*.*.*.*.*.*.*.*.*.*
|
||||||
|
name: "metric_multi"
|
||||||
|
labels:
|
||||||
|
label1: "$1"
|
||||||
|
label2: "$2"
|
||||||
|
label3: "$3"
|
||||||
|
label4: "$4"
|
||||||
|
label5: "$5"
|
||||||
|
label6: "$6"
|
||||||
|
label7: "$7"
|
||||||
|
label8: "$8"
|
||||||
|
label9: "$9"
|
||||||
|
label10: "$10"
|
||||||
|
label11: "$11"
|
||||||
|
label12: "$12"
|
||||||
|
`
|
||||||
|
mappings := mappings{
|
||||||
|
"metric.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkRegexMultipleCapturesDifferentLabels(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
mappings:
|
||||||
|
- match: metric\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)\.([^.]*)
|
||||||
|
name: "metric_multi"
|
||||||
|
match_type: regex
|
||||||
|
labels:
|
||||||
|
label1: "$1"
|
||||||
|
label2: "$2"
|
||||||
|
label3: "$3"
|
||||||
|
label4: "$4"
|
||||||
|
label5: "$5"
|
||||||
|
label6: "$6"
|
||||||
|
label7: "$7"
|
||||||
|
label8: "$8"
|
||||||
|
label9: "$9"
|
||||||
|
label10: "$10"
|
||||||
|
label11: "$11"
|
||||||
|
label12: "$12"
|
||||||
|
`
|
||||||
|
mappings := mappings{
|
||||||
|
"metric.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkGlob10Rules(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
mappings:` + duplicateRules(100, ruleTemplateSingleMatchGlob)
|
||||||
|
mappings := mappings{
|
||||||
|
"metric100.a": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkRegex10RulesAverage(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
defaults:
|
||||||
|
match_type: regex
|
||||||
|
mappings:` + duplicateRules(10, ruleTemplateSingleMatchRegex)
|
||||||
|
mappings := mappings{
|
||||||
|
"metric5.a": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkGlob100Rules(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
mappings:` + duplicateRules(100, ruleTemplateSingleMatchGlob)
|
||||||
|
mappings := mappings{
|
||||||
|
"metric100.a": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkGlob100RulesNoMatch(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
mappings:` + duplicateRules(100, ruleTemplateSingleMatchGlob)
|
||||||
|
mappings := mappings{
|
||||||
|
"metricnomatchy.a": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkGlob100RulesNoOrderingNoMatch(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
defaults:
|
||||||
|
glob_disable_ordering: true
|
||||||
|
mappings:` + duplicateRules(100, ruleTemplateSingleMatchGlob)
|
||||||
|
mappings := mappings{
|
||||||
|
"metricnomatchy.a": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkRegex100RulesAverage(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
defaults:
|
||||||
|
match_type: regex
|
||||||
|
mappings:` + duplicateRules(100, ruleTemplateSingleMatchRegex)
|
||||||
|
mappings := mappings{
|
||||||
|
"metric50.a": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkRegex100RulesWorst(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
defaults:
|
||||||
|
match_type: regex
|
||||||
|
mappings:` + duplicateRules(100, ruleTemplateSingleMatchRegex)
|
||||||
|
mappings := mappings{
|
||||||
|
"metric100.a": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkGlob100RulesMultipleCaptures(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
mappings:` + duplicateRules(100, ruleTemplateMultipleMatchGlob)
|
||||||
|
mappings := mappings{
|
||||||
|
"metric50.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkRegex100RulesMultipleCapturesAverage(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
defaults:
|
||||||
|
match_type: regex
|
||||||
|
mappings:` + duplicateRules(100, ruleTemplateMultipleMatchRegex)
|
||||||
|
mappings := mappings{
|
||||||
|
"metric50.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkRegex100RulesMultipleCapturesWorst(b *testing.B) {
|
||||||
|
config := `---
|
||||||
|
defaults:
|
||||||
|
match_type: regex
|
||||||
|
mappings:` + duplicateRules(100, ruleTemplateMultipleMatchRegex)
|
||||||
|
mappings := mappings{
|
||||||
|
"metric100.a.b.c.d.e.f.g.h.i.j.k.l": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper := MetricMapper{}
|
||||||
|
err := mapper.InitFromYAMLString(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("Config load error: %s %s", config, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dummyMetricType MetricType
|
||||||
|
b.ResetTimer()
|
||||||
|
for j := 0; j < b.N; j++ {
|
||||||
|
for metric := range mappings {
|
||||||
|
mapper.GetMapping(metric, dummyMetricType)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue