mirror of
https://github.com/portainer/portainer.git
synced 2026-06-23 06:10:13 +00:00
83 lines
2.1 KiB
Go
83 lines
2.1 KiB
Go
package libprometheus
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"time"
|
|
|
|
dto "github.com/prometheus/client_model/go"
|
|
"github.com/prometheus/common/expfmt"
|
|
prommodel "github.com/prometheus/common/model"
|
|
"github.com/prometheus/prometheus/model/labels"
|
|
"github.com/prometheus/prometheus/storage"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
// AppendExpositionSamples parses Prometheus exposition-format metrics from r
|
|
// and appends them as samples to the given Appendable.
|
|
func AppendExpositionSamples(ctx context.Context, db storage.Appendable, r io.Reader) error {
|
|
parser := expfmt.NewTextParser(prommodel.UTF8Validation)
|
|
metricFamilies, err := parser.TextToMetricFamilies(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
app := db.Appender(ctx)
|
|
now := time.Now().UnixMilli()
|
|
|
|
for name, mf := range metricFamilies {
|
|
if !supportsScalarMetricType(mf.GetType()) {
|
|
continue
|
|
}
|
|
|
|
for _, m := range mf.GetMetric() {
|
|
lbls := LabelsFromMetric(name, m)
|
|
value := ValueFromMetric(m, mf.GetType())
|
|
if _, err := app.Append(0, lbls, now, value); err != nil {
|
|
log.Debug().Err(err).Str("metric", name).Msg("failed to append metric sample")
|
|
}
|
|
}
|
|
}
|
|
|
|
return app.Commit()
|
|
}
|
|
|
|
func supportsScalarMetricType(mtype dto.MetricType) bool {
|
|
switch mtype {
|
|
case dto.MetricType_COUNTER, dto.MetricType_GAUGE, dto.MetricType_UNTYPED:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// LabelsFromMetric builds a labels.Labels from a metric name and its label pairs.
|
|
func LabelsFromMetric(name string, m *dto.Metric) labels.Labels {
|
|
b := labels.NewScratchBuilder(1 + len(m.GetLabel()))
|
|
b.Add(string(prommodel.MetricNameLabel), name)
|
|
for _, lp := range m.GetLabel() {
|
|
b.Add(lp.GetName(), lp.GetValue())
|
|
}
|
|
b.Sort()
|
|
return b.Labels()
|
|
}
|
|
|
|
// ValueFromMetric extracts the numeric value from a metric based on its type.
|
|
func ValueFromMetric(m *dto.Metric, mtype dto.MetricType) float64 {
|
|
switch mtype {
|
|
case dto.MetricType_COUNTER:
|
|
if c := m.GetCounter(); c != nil {
|
|
return c.GetValue()
|
|
}
|
|
case dto.MetricType_GAUGE:
|
|
if g := m.GetGauge(); g != nil {
|
|
return g.GetValue()
|
|
}
|
|
case dto.MetricType_UNTYPED:
|
|
if u := m.GetUntyped(); u != nil {
|
|
return u.GetValue()
|
|
}
|
|
}
|
|
return 0
|
|
}
|