in otelcollector/prometheusreceiver/internal/transaction.go [249:307]
func (t *transaction) AppendHistogram(_ storage.SeriesRef, ls labels.Labels, atMs int64, h *histogram.Histogram, fh *histogram.FloatHistogram) (storage.SeriesRef, error) {
if !t.enableNativeHistograms {
return 0, nil
}
select {
case <-t.ctx.Done():
return 0, errTransactionAborted
default:
}
if t.externalLabels.Len() != 0 {
b := labels.NewBuilder(ls)
t.externalLabels.Range(func(l labels.Label) {
b.Set(l.Name, l.Value)
})
ls = b.Labels()
}
rKey, err := t.initTransaction(ls)
if err != nil {
return 0, err
}
// Any datapoint with duplicate labels MUST be rejected per:
// * https://github.com/open-telemetry/wg-prometheus/issues/44
// * https://github.com/open-telemetry/opentelemetry-collector/issues/3407
// as Prometheus rejects such too as of version 2.16.0, released on 2020-02-13.
if dupLabel, hasDup := ls.HasDuplicateLabelNames(); hasDup {
return 0, fmt.Errorf("invalid sample: non-unique label names: %q", dupLabel)
}
metricName := ls.Get(model.MetricNameLabel)
if metricName == "" {
return 0, errMetricNameNotFound
}
// The `up`, `target_info`, `otel_scope_info` metrics should never generate native histograms,
// thus we don't check for them here as opposed to the Append function.
curMF, existing := t.getOrCreateMetricFamily(*rKey, getScopeID(ls), metricName)
if !existing {
curMF.mtype = pmetric.MetricTypeExponentialHistogram
} else if curMF.mtype != pmetric.MetricTypeExponentialHistogram {
// Already scraped as classic histogram.
return 0, nil
}
if h != nil && h.CounterResetHint == histogram.GaugeType || fh != nil && fh.CounterResetHint == histogram.GaugeType {
t.logger.Warn("dropping unsupported gauge histogram datapoint", zap.String("metric_name", metricName), zap.Any("labels", ls))
}
err = curMF.addExponentialHistogramSeries(t.getSeriesRef(ls, curMF.mtype), metricName, ls, atMs, h, fh)
if err != nil {
t.logger.Warn("failed to add histogram datapoint", zap.Error(err), zap.String("metric_name", metricName), zap.Any("labels", ls))
}
return 0, nil // never return errors, as that fails the whole scrape
}