telegraf/plugins/serializers/prometheus/convert.go

176 lines
3.6 KiB
Go
Raw Normal View History

package prometheus
import (
"strings"
"unicode"
"github.com/influxdata/telegraf"
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,
}
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
},
LatinOffset: 4,
}
func isValid(name string) bool {
if name == "" {
return false
}
for i, r := range name {
switch {
case i == 0:
if !unicode.In(r, FirstTable) {
return false
}
default:
if !unicode.In(r, RestTable) {
return false
}
}
}
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) {
return name, true
}
var b strings.Builder
for i, r := range name {
switch {
case i == 0:
if unicode.In(r, FirstTable) {
b.WriteRune(r)
}
default:
if unicode.In(r, RestTable) {
b.WriteRune(r)
} else {
b.WriteString("_")
}
}
}
name = strings.Trim(b.String(), "_")
if name == "" {
return "", false
}
return name, true
}
// MetricName returns the Prometheus metric name.
func MetricName(measurement, fieldKey string, valueType telegraf.ValueType) string {
switch valueType {
case telegraf.Histogram, telegraf.Summary:
switch {
case strings.HasSuffix(fieldKey, "_bucket"):
fieldKey = strings.TrimSuffix(fieldKey, "_bucket")
case strings.HasSuffix(fieldKey, "_sum"):
fieldKey = strings.TrimSuffix(fieldKey, "_sum")
case strings.HasSuffix(fieldKey, "_count"):
fieldKey = strings.TrimSuffix(fieldKey, "_count")
}
}
if measurement == "prometheus" {
return fieldKey
}
return measurement + "_" + fieldKey
}
func MetricType(valueType telegraf.ValueType) *dto.MetricType {
switch valueType {
case telegraf.Counter:
return dto.MetricType_COUNTER.Enum()
case telegraf.Gauge:
return dto.MetricType_GAUGE.Enum()
case telegraf.Summary:
return dto.MetricType_SUMMARY.Enum()
case telegraf.Untyped:
return dto.MetricType_UNTYPED.Enum()
case telegraf.Histogram:
return dto.MetricType_HISTOGRAM.Enum()
default:
panic("unknown telegraf.ValueType")
}
}
// SampleValue converts a field value into a value suitable for a simple sample value.
func SampleValue(value interface{}) (float64, bool) {
switch v := value.(type) {
case float64:
return v, true
case int64:
return float64(v), true
case uint64:
return float64(v), true
case bool:
if v {
return 1.0, true
}
return 0.0, true
default:
return 0, false
}
}
// SampleCount converts a field value into a count suitable for a metric family
// of the Histogram or Summary type.
func SampleCount(value interface{}) (uint64, bool) {
switch v := value.(type) {
case float64:
if v < 0 {
return 0, false
}
return uint64(v), true
case int64:
if v < 0 {
return 0, false
}
return uint64(v), true
case uint64:
return v, true
default:
return 0, false
}
}
// SampleSum converts a field value into a sum suitable for a metric family
// of the Histogram or Summary type.
func SampleSum(value interface{}) (float64, bool) {
switch v := value.(type) {
case float64:
return v, true
case int64:
return float64(v), true
case uint64:
return float64(v), true
default:
return 0, false
}
}