Merge pull request #98 from drawks/remove_legacy_mapper

Removes support for legacy mapper config
This commit is contained in:
Ben Kochie 2017-09-29 10:08:08 +02:00 committed by GitHub
commit 9accf494a9
3 changed files with 15 additions and 292 deletions

View file

@ -98,36 +98,6 @@ In general, the different metric types are translated as follows:
An example mapping configuration: An example mapping configuration:
# comments are allowed
test.dispatcher.*.*.*
name="dispatcher_events_total"
processor="$1"
action="$2"
outcome="$3"
job="test_dispatcher"
*.signup.*.*
name="signup_events_total"
provider="$2"
outcome="$3"
job="${1}_server"
This would transform these example StatsD metrics into Prometheus metrics as
follows:
test.dispatcher.FooProcessor.send.success
=> dispatcher_events_total{processor="FooProcessor", action="send", outcome="success", job="test_dispatcher"}
foo_product.signup.facebook.failure
=> signup_events_total{provider="facebook", outcome="failure", job="foo_product_server"}
test.web-server.foo.bar
=> test_web__server_foo_bar{}
YAML may also be used for the configuration if the passed filename ends in `.yml` or
`.yaml`. The above example mapping, in YAML, would be:
```yaml ```yaml
mappings: mappings:
- match: test.dispatcher.*.*.* - match: test.dispatcher.*.*.*
@ -145,7 +115,20 @@ mappings:
job: "${1}_server" job: "${1}_server"
``` ```
Using the YAML configuration, one may also set the timer type to "histogram". The This would transform these example StatsD metrics into Prometheus metrics as
follows:
test.dispatcher.FooProcessor.send.success
=> dispatcher_events_total{processor="FooProcessor", action="send", outcome="success", job="test_dispatcher"}
foo_product.signup.facebook.failure
=> signup_events_total{provider="facebook", outcome="failure", job="foo_product_server"}
test.web-server.foo.bar
=> test_web__server_foo_bar{}
In the configuration, one may also set the timer type to "histogram". The
default is "summary" as in the plain text configuration format. For example, default is "summary" as in the plain text configuration format. For example,
to set the timer type for a single metric: to set the timer type for a single metric:

View file

@ -16,7 +16,6 @@ package main
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"path/filepath"
"regexp" "regexp"
"strings" "strings"
"sync" "sync"
@ -55,78 +54,6 @@ type metricMapping struct {
MatchType matchType `yaml:"match_type"` MatchType matchType `yaml:"match_type"`
} }
type configLoadStates int
const (
SEARCHING configLoadStates = iota
METRIC_DEFINITION
)
func (m *metricMapper) initFromString(fileContents string) error {
lines := strings.Split(fileContents, "\n")
numLines := len(lines)
state := SEARCHING
parsedMappings := []metricMapping{}
currentMapping := metricMapping{Labels: prometheus.Labels{}}
for i, line := range lines {
line = strings.TrimSpace(line)
// skip comments
if strings.HasPrefix(line, "#") {
continue
}
switch state {
case SEARCHING:
if line == "" {
continue
}
if !metricLineRE.MatchString(line) {
return fmt.Errorf("line %d: expected metric match line, got: %s", i, line)
}
// Translate the glob-style metric match line into a proper regex that we
// can use to match metrics later on.
metricRe := strings.Replace(line, ".", "\\.", -1)
metricRe = strings.Replace(metricRe, "*", "([^.]+)", -1)
currentMapping.regex = regexp.MustCompile("^" + metricRe + "$")
state = METRIC_DEFINITION
case METRIC_DEFINITION:
if (i == numLines-1) && (line != "") {
return fmt.Errorf("Line %d: missing terminating newline", i)
}
if line == "" {
if len(currentMapping.Labels) == 0 {
return fmt.Errorf("Line %d: metric mapping didn't set any labels", i)
}
if _, ok := currentMapping.Labels["name"]; !ok {
return fmt.Errorf("Line %d: metric mapping didn't set a metric name", i)
}
parsedMappings = append(parsedMappings, currentMapping)
state = SEARCHING
currentMapping = metricMapping{Labels: prometheus.Labels{}}
continue
}
if err := m.updateMapping(line, i, &currentMapping); err != nil {
return err
}
default:
panic("illegal state")
}
}
m.mutex.Lock()
defer m.mutex.Unlock()
m.Mappings = parsedMappings
mappingsCount.Set(float64(len(parsedMappings)))
return nil
}
func (m *metricMapper) initFromYAMLString(fileContents string) error { func (m *metricMapper) initFromYAMLString(fileContents string) error {
var n metricMapper var n metricMapper
@ -201,12 +128,7 @@ func (m *metricMapper) initFromFile(fileName string) error {
if err != nil { if err != nil {
return err return err
} }
switch strings.ToLower(filepath.Ext(fileName)) { return m.initFromYAMLString(string(mappingStr))
case ".yaml", ".yml":
return m.initFromYAMLString(string(mappingStr))
default:
return m.initFromString(string(mappingStr))
}
} }
func (m *metricMapper) getMapping(statsdMetric string) (*metricMapping, prometheus.Labels, bool) { func (m *metricMapper) getMapping(statsdMetric string) (*metricMapping, prometheus.Labels, bool) {
@ -229,16 +151,3 @@ func (m *metricMapper) getMapping(statsdMetric string) (*metricMapping, promethe
return nil, nil, false return nil, nil, false
} }
func (m *metricMapper) updateMapping(line string, i int, mapping *metricMapping) error {
matches := labelLineRE.FindStringSubmatch(line)
if len(matches) != 3 {
return fmt.Errorf("Line %d: expected label mapping line, got: %s", i, line)
}
label, value := matches[1], matches[2]
if label == "name" && !metricNameRE.MatchString(value) {
return fmt.Errorf("Line %d: metric name '%s' doesn't match regex '%s'", i, value, metricNameRE)
}
(*mapping).Labels[label] = value
return nil
}

View file

@ -17,175 +17,6 @@ import (
"testing" "testing"
) )
func TestMetricMapper(t *testing.T) {
scenarios := []struct {
config string
configBad bool
mappings map[string]map[string]string
}{
// Empty config.
{},
// Config with several mapping definitions.
{
config: `
# this is a comment
# this is another
test.dispatcher.*.*.*
name="dispatch_events"
processor="$1"
action="$2"
result="$3"
# here is a third
job="test_dispatcher"
test.my-dispatch-host01.name.dispatcher.*.*.*
name="host_dispatch_events"
processor="$1"
action="$2"
result="$3"
job="test_dispatcher"
*.*
name="catchall"
first="$1"
second="$2"
third="$3"
job="$1-$2-$3"
`,
mappings: map[string]map[string]string{
"test.dispatcher.FooProcessor.send.succeeded": map[string]string{
"name": "dispatch_events",
"processor": "FooProcessor",
"action": "send",
"result": "succeeded",
"job": "test_dispatcher",
},
"test.my-dispatch-host01.name.dispatcher.FooProcessor.send.succeeded": map[string]string{
"name": "host_dispatch_events",
"processor": "FooProcessor",
"action": "send",
"result": "succeeded",
"job": "test_dispatcher",
},
"foo.bar": map[string]string{
"name": "catchall",
"first": "foo",
"second": "bar",
"third": "",
"job": "foo-bar-",
},
"foo.bar.baz": map[string]string{},
},
},
// Config with bad regex reference.
{
config: `
test.*
name="name"
label="$1_foo"
`,
mappings: map[string]map[string]string{
"test.a": map[string]string{
"name": "name",
"label": "",
},
},
},
// Config with good regex reference.
{
config: `
test.*
name="name"
label="${1}_foo"
`,
mappings: map[string]map[string]string{
"test.a": map[string]string{
"name": "name",
"label": "a_foo",
},
},
},
// Config with bad metric line.
{
config: `
bad--metric-line.*.*
name="foo"
`,
configBad: true,
},
// Config with bad label line.
{
config: `
test.*.*
name=foo
`,
configBad: true,
},
// Config with bad label line.
{
config: `
test.*.*
name="foo-name"
`,
configBad: true,
},
// Config with bad metric name.
{
config: `
test.*.*
name="0foo"
`,
configBad: true,
},
// A single mapping config without a terminating newline.
{
config: `
test.*
name="name"
label="foo"`,
configBad: true,
},
// Multiple mapping configs and no terminating newline.
{
config: `
test.bar
name="name_bar"
label="foo"
test.foo
name="name_foo"
label="bar"`,
configBad: true,
},
}
mapper := metricMapper{}
for i, scenario := range scenarios {
err := mapper.initFromString(scenario.config)
if err != nil && !scenario.configBad {
t.Fatalf("%d. Config load error: %s", i, err)
}
if err == nil && scenario.configBad {
t.Fatalf("%d. Expected bad config, but loaded ok", i)
}
for metric, mapping := range scenario.mappings {
_, labels, present := mapper.getMapping(metric)
if len(labels) == 0 && present {
t.Fatalf("%d.%q: Expected metric to not be present", i, metric)
}
if len(labels) != len(mapping) {
t.Fatalf("%d.%q: Expected %d labels, got %d", i, metric, len(mapping), len(labels))
}
for label, value := range labels {
if mapping[label] != value {
t.Fatalf("%d.%q: Expected labels %v, got %v", i, metric, mapping, labels)
}
}
}
}
}
func TestMetricMapperYAML(t *testing.T) { func TestMetricMapperYAML(t *testing.T) {
scenarios := []struct { scenarios := []struct {
config string config string