Skip to content

Commit

Permalink
Use a custom collector to avoid checking labels
Browse files Browse the repository at this point in the history
In order to avoid checking label sets stay the same across all the
emitted metrics, use a custom collector instead of going over one of
prometheus' provided ones. Because of the use case (create a registry,
discard it after one time), this probably also reduces the resource
usage.

The reason for this workaround is that in case of failure, the emitted
metrics have different labelsets. Specifically, labels describing the
error are added. If we end up with a mix of successful and unsuccessful
requests, prometheus will reject one of the metrics because they are
using different sets of labels.

Reevaluate this later.

Signed-off-by: Marcelo E. Magallon <marcelo.magallon@grafana.com>
  • Loading branch information
mem committed Jun 12, 2023
1 parent 2612699 commit c69aeb6
Showing 1 changed file with 28 additions and 7 deletions.
35 changes: 28 additions & 7 deletions internal/k6runner/k6runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,26 @@ func (r Script) Run(ctx context.Context, registry *prometheus.Registry, logger l
return nil
}

type customCollector struct {
metrics []prometheus.Metric
}

func (c *customCollector) Describe(ch chan<- *prometheus.Desc) {
// We do not send any descriptions in order to create an unchecked
// metric. This allows us to have a metric with the same name and
// different label values.
//
// TODO(mem): reevaluate if this is really want we want to do.
}

func (c *customCollector) Collect(ch chan<- prometheus.Metric) {
for _, m := range c.metrics {
ch <- m
}
}

func textToRegistry(metrics []byte, registry prometheus.Registerer, logger zerolog.Logger) error {
collector := &customCollector{}
promDecoder := expfmt.NewDecoder(bytes.NewBuffer(metrics), expfmt.FmtText)
decoderOpts := expfmt.DecodeOptions{Timestamp: model.Now()}
for {
Expand Down Expand Up @@ -117,21 +136,23 @@ func textToRegistry(metrics []byte, registry prometheus.Registerer, logger zerol

delete(sample.Metric, model.MetricNameLabel)

g := prometheus.NewGauge(prometheus.GaugeOpts{
Name: string(name),
ConstLabels: metricToLabels(sample.Metric),
})

err := registry.Register(g)
desc := prometheus.NewDesc(string(name), mf.GetHelp(), nil, metricToLabels(sample.Metric))
// TODO(mem): maybe change this to untyped?
m, err := prometheus.NewConstMetric(desc, prometheus.GaugeValue, float64(sample.Value))
if err != nil {
logger.Error().Err(err).Msg("creating prometheus metric")
return err
}

g.Set(float64(sample.Value))
collector.metrics = append(collector.metrics, m)
}

case io.EOF:
// nothing was returned, we are done
if err := registry.Register(collector); err != nil {
return err
}

return nil

default:
Expand Down

0 comments on commit c69aeb6

Please sign in to comment.