Allow colons in the prometheus metric name (#6751)
This commit is contained in:
parent
09f9b70354
commit
1f7b68a2b2
|
@ -113,7 +113,7 @@ func (c *Collection) createLabels(metric telegraf.Metric) []LabelPair {
|
|||
}
|
||||
}
|
||||
|
||||
name, ok := SanitizeName(tag.Key)
|
||||
name, ok := SanitizeLabelName(tag.Key)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ func (c *Collection) createLabels(metric telegraf.Metric) []LabelPair {
|
|||
continue
|
||||
}
|
||||
|
||||
name, ok := SanitizeName(field.Key)
|
||||
name, ok := SanitizeLabelName(field.Key)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ func (c *Collection) Add(metric telegraf.Metric) {
|
|||
labels := c.createLabels(metric)
|
||||
for _, field := range metric.FieldList() {
|
||||
metricName := MetricName(metric.Name(), field.Key, metric.Type())
|
||||
metricName, ok := SanitizeName(metricName)
|
||||
metricName, ok := SanitizeMetricName(metricName)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -8,26 +8,53 @@ import (
|
|||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
var FirstTable = &unicode.RangeTable{
|
||||
R16: []unicode.Range16{
|
||||
{0x0041, 0x005A, 1}, // A-Z
|
||||
{0x005F, 0x005F, 1}, // _
|
||||
{0x0061, 0x007A, 1}, // a-z
|
||||
},
|
||||
LatinOffset: 3,
|
||||
type Table struct {
|
||||
First *unicode.RangeTable
|
||||
Rest *unicode.RangeTable
|
||||
}
|
||||
|
||||
var RestTable = &unicode.RangeTable{
|
||||
R16: []unicode.Range16{
|
||||
{0x0030, 0x0039, 1}, // 0-9
|
||||
{0x0041, 0x005A, 1}, // A-Z
|
||||
{0x005F, 0x005F, 1}, // _
|
||||
{0x0061, 0x007A, 1}, // a-z
|
||||
var MetricNameTable = Table{
|
||||
First: &unicode.RangeTable{
|
||||
R16: []unicode.Range16{
|
||||
{0x003A, 0x003A, 1}, // :
|
||||
{0x0041, 0x005A, 1}, // A-Z
|
||||
{0x005F, 0x005F, 1}, // _
|
||||
{0x0061, 0x007A, 1}, // a-z
|
||||
},
|
||||
LatinOffset: 4,
|
||||
},
|
||||
Rest: &unicode.RangeTable{
|
||||
R16: []unicode.Range16{
|
||||
{0x0030, 0x003A, 1}, // 0-:
|
||||
{0x0041, 0x005A, 1}, // A-Z
|
||||
{0x005F, 0x005F, 1}, // _
|
||||
{0x0061, 0x007A, 1}, // a-z
|
||||
},
|
||||
LatinOffset: 4,
|
||||
},
|
||||
LatinOffset: 4,
|
||||
}
|
||||
|
||||
func isValid(name string) bool {
|
||||
var LabelNameTable = Table{
|
||||
First: &unicode.RangeTable{
|
||||
R16: []unicode.Range16{
|
||||
{0x0041, 0x005A, 1}, // A-Z
|
||||
{0x005F, 0x005F, 1}, // _
|
||||
{0x0061, 0x007A, 1}, // a-z
|
||||
},
|
||||
LatinOffset: 3,
|
||||
},
|
||||
Rest: &unicode.RangeTable{
|
||||
R16: []unicode.Range16{
|
||||
{0x0030, 0x0039, 1}, // 0-9
|
||||
{0x0041, 0x005A, 1}, // A-Z
|
||||
{0x005F, 0x005F, 1}, // _
|
||||
{0x0061, 0x007A, 1}, // a-z
|
||||
},
|
||||
LatinOffset: 4,
|
||||
},
|
||||
}
|
||||
|
||||
func isValid(name string, table Table) bool {
|
||||
if name == "" {
|
||||
return false
|
||||
}
|
||||
|
@ -35,11 +62,11 @@ func isValid(name string) bool {
|
|||
for i, r := range name {
|
||||
switch {
|
||||
case i == 0:
|
||||
if !unicode.In(r, FirstTable) {
|
||||
if !unicode.In(r, table.First) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !unicode.In(r, RestTable) {
|
||||
if !unicode.In(r, table.Rest) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -48,12 +75,11 @@ func isValid(name string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// SanitizeName check if the name is a valid Prometheus metric name and label
|
||||
// name. If not, it attempts to replaces invalid runes with an underscore to
|
||||
// create a valid name. Returns the metric name and true if the name is valid
|
||||
// to use.
|
||||
func SanitizeName(name string) (string, bool) {
|
||||
if isValid(name) {
|
||||
// Sanitize checks if the name is valid according to the table. If not, it
|
||||
// attempts to replaces invalid runes with an underscore to create a valid
|
||||
// name.
|
||||
func sanitize(name string, table Table) (string, bool) {
|
||||
if isValid(name, table) {
|
||||
return name, true
|
||||
}
|
||||
|
||||
|
@ -62,11 +88,11 @@ func SanitizeName(name string) (string, bool) {
|
|||
for i, r := range name {
|
||||
switch {
|
||||
case i == 0:
|
||||
if unicode.In(r, FirstTable) {
|
||||
if unicode.In(r, table.First) {
|
||||
b.WriteRune(r)
|
||||
}
|
||||
default:
|
||||
if unicode.In(r, RestTable) {
|
||||
if unicode.In(r, table.Rest) {
|
||||
b.WriteRune(r)
|
||||
} else {
|
||||
b.WriteString("_")
|
||||
|
@ -82,6 +108,20 @@ func SanitizeName(name string) (string, bool) {
|
|||
return name, true
|
||||
}
|
||||
|
||||
// SanitizeMetricName checks if the name is a valid Prometheus metric name. If
|
||||
// not, it attempts to replaces invalid runes with an underscore to create a
|
||||
// valid name.
|
||||
func SanitizeMetricName(name string) (string, bool) {
|
||||
return sanitize(name, MetricNameTable)
|
||||
}
|
||||
|
||||
// SanitizeLabelName checks if the name is a valid Prometheus label name. If
|
||||
// not, it attempts to replaces invalid runes with an underscore to create a
|
||||
// valid name.
|
||||
func SanitizeLabelName(name string) (string, bool) {
|
||||
return sanitize(name, LabelNameTable)
|
||||
}
|
||||
|
||||
// MetricName returns the Prometheus metric name.
|
||||
func MetricName(measurement, fieldKey string, valueType telegraf.ValueType) string {
|
||||
switch valueType {
|
||||
|
|
|
@ -409,6 +409,42 @@ rpc_duration_seconds_count 2693
|
|||
# HELP cpu_time_idle Telegraf collected metric
|
||||
# TYPE cpu_time_idle untyped
|
||||
cpu_time_idle 43
|
||||
`),
|
||||
},
|
||||
{
|
||||
name: "colons are not replaced in metric name from measurement",
|
||||
metrics: []telegraf.Metric{
|
||||
testutil.MustMetric(
|
||||
"cpu::xyzzy",
|
||||
map[string]string{},
|
||||
map[string]interface{}{
|
||||
"time_idle": 42.0,
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
},
|
||||
expected: []byte(`
|
||||
# HELP cpu::xyzzy_time_idle Telegraf collected metric
|
||||
# TYPE cpu::xyzzy_time_idle untyped
|
||||
cpu::xyzzy_time_idle 42
|
||||
`),
|
||||
},
|
||||
{
|
||||
name: "colons are not replaced in metric name from field",
|
||||
metrics: []telegraf.Metric{
|
||||
testutil.MustMetric(
|
||||
"cpu",
|
||||
map[string]string{},
|
||||
map[string]interface{}{
|
||||
"time:idle": 42.0,
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
},
|
||||
expected: []byte(`
|
||||
# HELP cpu_time:idle Telegraf collected metric
|
||||
# TYPE cpu_time:idle untyped
|
||||
cpu_time:idle 42
|
||||
`),
|
||||
},
|
||||
{
|
||||
|
@ -429,6 +465,26 @@ cpu_time_idle 43
|
|||
# HELP cpu_time_idle Telegraf collected metric
|
||||
# TYPE cpu_time_idle untyped
|
||||
cpu_time_idle{host_name="example.org"} 42
|
||||
`),
|
||||
},
|
||||
{
|
||||
name: "colons are replaced in label name",
|
||||
metrics: []telegraf.Metric{
|
||||
testutil.MustMetric(
|
||||
"cpu",
|
||||
map[string]string{
|
||||
"host:name": "example.org",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"time_idle": 42.0,
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
),
|
||||
},
|
||||
expected: []byte(`
|
||||
# HELP cpu_time_idle Telegraf collected metric
|
||||
# TYPE cpu_time_idle untyped
|
||||
cpu_time_idle{host_name="example.org"} 42
|
||||
`),
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue