diff --git a/bridge.go b/bridge.go index bb86487..89447d0 100644 --- a/bridge.go +++ b/bridge.go @@ -10,12 +10,17 @@ import ( "fmt" "log" "net" + "regexp" "strconv" "strings" "github.com/prometheus/client_golang/prometheus" ) +var ( + illegalCharsRE = regexp.MustCompile(`[^a-zA-Z0-9_]`) +) + type CounterContainer struct { Elements map[string]prometheus.Counter } @@ -121,10 +126,13 @@ type Bridge struct { } func escapeMetricName(metricName string) string { - // TODO: evaluate what kind of escaping we really want. - metricName = strings.Replace(metricName, "_", "__", -1) - metricName = strings.Replace(metricName, "-", "__", -1) - metricName = strings.Replace(metricName, ".", "_", -1) + // If a metric starts with a digit, prepend an underscore. + if metricName[0] >= '0' && metricName[0] <= '9' { + metricName = "_" + metricName + } + + // Replace all illegal metric chars with underscores. + metricName = illegalCharsRE.ReplaceAllString(metricName, "_") return metricName } diff --git a/mapper.go b/mapper.go index 7cd374c..12162b2 100644 --- a/mapper.go +++ b/mapper.go @@ -20,6 +20,7 @@ var ( identifierRE = `[a-zA-Z_][a-zA-Z0-9_]+` metricLineRE = regexp.MustCompile(`^(\*\.|` + identifierRE + `\.)+(\*|` + identifierRE + `)$`) labelLineRE = regexp.MustCompile(`^(` + identifierRE + `)\s*=\s*"(.*)"$`) + metricNameRE = regexp.MustCompile(`^` + identifierRE + `$`) ) type metricMapping struct { @@ -85,7 +86,11 @@ func (m *metricMapper) initFromString(fileContents string) error { if len(matches) != 3 { return fmt.Errorf("Line %d: expected label mapping line, got: %s", i, line) } - currentMapping.labels[matches[1]] = matches[2] + 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) + } + currentMapping.labels[label] = value default: panic("illegal state") } diff --git a/mapper_test.go b/mapper_test.go index 87ca71a..6b9ccb2 100644 --- a/mapper_test.go +++ b/mapper_test.go @@ -69,6 +69,14 @@ func TestMetricMapper(t *testing.T) { `, configBad: true, }, + // Config with bad metric name. + { + config: ` + test.*.* + name="0foo" + `, + configBad: true, + }, } mapper := metricMapper{}