mirror of
https://github.com/wahyd4/telegraf.git
synced 2026-08-16 16:16:37 +10:00
Metrics type summary should retrieve values via GetSummary while histogram should retrieve values via GetHistogram for both count and sum
172 lines
4.5 KiB
Go
172 lines
4.5 KiB
Go
package prometheus
|
|
|
|
// Parser inspired from
|
|
// https://github.com/prometheus/prom2json/blob/master/main.go
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"math"
|
|
"mime"
|
|
|
|
"github.com/influxdata/telegraf"
|
|
|
|
"github.com/matttproud/golang_protobuf_extensions/pbutil"
|
|
dto "github.com/prometheus/client_model/go"
|
|
"github.com/prometheus/common/expfmt"
|
|
)
|
|
|
|
// PrometheusParser is an object for Parsing incoming metrics.
|
|
type PrometheusParser struct {
|
|
// PromFormat
|
|
PromFormat map[string]string
|
|
// DefaultTags will be added to every parsed metric
|
|
// DefaultTags map[string]string
|
|
}
|
|
|
|
// Parse returns a slice of Metrics from a text representation of a
|
|
// metrics
|
|
func (p *PrometheusParser) Parse(buf []byte) ([]telegraf.Metric, error) {
|
|
var metrics []telegraf.Metric
|
|
var parser expfmt.TextParser
|
|
// parse even if the buffer begins with a newline
|
|
buf = bytes.TrimPrefix(buf, []byte("\n"))
|
|
// Read raw data
|
|
buffer := bytes.NewBuffer(buf)
|
|
reader := bufio.NewReader(buffer)
|
|
|
|
// Get format
|
|
mediatype, params, err := mime.ParseMediaType(p.PromFormat["Content-Type"])
|
|
// Prepare output
|
|
metricFamilies := make(map[string]*dto.MetricFamily)
|
|
if err == nil && mediatype == "application/vnd.google.protobuf" &&
|
|
params["encoding"] == "delimited" &&
|
|
params["proto"] == "io.prometheus.client.MetricFamily" {
|
|
for {
|
|
metricFamily := &dto.MetricFamily{}
|
|
if _, err = pbutil.ReadDelimited(reader, metricFamily); err != nil {
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
return nil, fmt.Errorf("reading metric family protocol buffer failed: %s", err)
|
|
}
|
|
metricFamilies[metricFamily.GetName()] = metricFamily
|
|
}
|
|
} else {
|
|
metricFamilies, err = parser.TextToMetricFamilies(reader)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("reading text format failed: %s", err)
|
|
}
|
|
// read metrics
|
|
for metricName, mf := range metricFamilies {
|
|
for _, m := range mf.Metric {
|
|
// reading tags
|
|
tags := makeLabels(m)
|
|
/*
|
|
for key, value := range p.DefaultTags {
|
|
tags[key] = value
|
|
}
|
|
*/
|
|
// reading fields
|
|
fields := make(map[string]interface{})
|
|
if mf.GetType() == dto.MetricType_SUMMARY {
|
|
// summary metric
|
|
fields = makeQuantiles(m)
|
|
fields["count"] = float64(m.GetSummary().GetSampleCount())
|
|
fields["sum"] = float64(m.GetSummary().GetSampleSum())
|
|
} else if mf.GetType() == dto.MetricType_HISTOGRAM {
|
|
// historgram metric
|
|
fields = makeBuckets(m)
|
|
fields["count"] = float64(m.GetHistogram().GetSampleCount())
|
|
fields["sum"] = float64(m.GetHistogram().GetSampleSum())
|
|
|
|
} else {
|
|
// standard metric
|
|
fields = getNameAndValue(m)
|
|
}
|
|
// converting to telegraf metric
|
|
if len(fields) > 0 {
|
|
metric, err := telegraf.NewMetric(metricName, tags, fields)
|
|
if err == nil {
|
|
metrics = append(metrics, metric)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return metrics, err
|
|
}
|
|
|
|
// Parse one line
|
|
func (p *PrometheusParser) ParseLine(line string) (telegraf.Metric, error) {
|
|
metrics, err := p.Parse([]byte(line + "\n"))
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(metrics) < 1 {
|
|
return nil, fmt.Errorf(
|
|
"Can not parse the line: %s, for data format: prometheus", line)
|
|
}
|
|
|
|
return metrics[0], nil
|
|
}
|
|
|
|
/*
|
|
// Set default tags
|
|
func (p *PrometheusParser) SetDefaultTags(tags map[string]string) {
|
|
p.DefaultTags = tags
|
|
}
|
|
*/
|
|
|
|
// Get Quantiles from summary metric
|
|
func makeQuantiles(m *dto.Metric) map[string]interface{} {
|
|
fields := make(map[string]interface{})
|
|
for _, q := range m.GetSummary().Quantile {
|
|
if !math.IsNaN(q.GetValue()) {
|
|
fields[fmt.Sprint(q.GetQuantile())] = float64(q.GetValue())
|
|
}
|
|
}
|
|
return fields
|
|
}
|
|
|
|
// Get Buckets from histogram metric
|
|
func makeBuckets(m *dto.Metric) map[string]interface{} {
|
|
fields := make(map[string]interface{})
|
|
for _, b := range m.GetHistogram().Bucket {
|
|
fields[fmt.Sprint(b.GetUpperBound())] = float64(b.GetCumulativeCount())
|
|
}
|
|
return fields
|
|
}
|
|
|
|
// Get labels from metric
|
|
func makeLabels(m *dto.Metric) map[string]string {
|
|
result := map[string]string{}
|
|
for _, lp := range m.Label {
|
|
result[lp.GetName()] = lp.GetValue()
|
|
}
|
|
return result
|
|
}
|
|
|
|
// Get name and value from metric
|
|
func getNameAndValue(m *dto.Metric) map[string]interface{} {
|
|
fields := make(map[string]interface{})
|
|
if m.Gauge != nil {
|
|
if !math.IsNaN(m.GetGauge().GetValue()) {
|
|
fields["gauge"] = float64(m.GetGauge().GetValue())
|
|
}
|
|
} else if m.Counter != nil {
|
|
if !math.IsNaN(m.GetGauge().GetValue()) {
|
|
fields["counter"] = float64(m.GetCounter().GetValue())
|
|
}
|
|
} else if m.Untyped != nil {
|
|
if !math.IsNaN(m.GetGauge().GetValue()) {
|
|
fields["value"] = float64(m.GetUntyped().GetValue())
|
|
}
|
|
}
|
|
return fields
|
|
}
|