mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-01-03 22:52:30 +02:00
Export non monotonic counters as gauge values from the prometheus exporter (#1269)
* Export non monotonic counters as gauge values from the prometheus exporter * Add a test to ensure the pre-existing LastValue pathway on the collector exports the last value * Add a TODO around refactoring the prometheus test to verify metadata as well Co-authored-by: Anthony Mirabella <a9@aneurysm9.com> Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
This commit is contained in:
parent
757030dc78
commit
b7508da6fa
@ -37,6 +37,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||
- Fix `Code.UnmarshalJSON` to work with valid json only. (#1276)
|
||||
- The `resource.New()` method changes signature to support builtin attributes and functional options, including `telemetry.sdk.*` and
|
||||
`host.name` semantic conventions; the former method is renamed `resource.NewWithAttributes`. (#1235)
|
||||
- The prometheus exporter now exports non-monotonic counters (i.e. `UpDownCounter`s) as gauges. (#1210)
|
||||
- Correct the `Span.End` method documentation in the `otel` API to state updates are not allowed on a span after it has ended. (#1310)
|
||||
|
||||
### Removed
|
||||
|
@ -214,6 +214,7 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) {
|
||||
err := ctrl.ForEach(c.exp, func(record export.Record) error {
|
||||
agg := record.Aggregation()
|
||||
numberKind := record.Descriptor().NumberKind()
|
||||
instrumentKind := record.Descriptor().InstrumentKind()
|
||||
|
||||
var labelKeys, labels []string
|
||||
mergeLabels(record, &labelKeys, &labels)
|
||||
@ -236,9 +237,13 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) {
|
||||
if err := c.exportSummary(ch, dist, numberKind, desc, labels); err != nil {
|
||||
return fmt.Errorf("exporting summary: %w", err)
|
||||
}
|
||||
} else if sum, ok := agg.(aggregation.Sum); ok {
|
||||
if err := c.exportCounter(ch, sum, numberKind, desc, labels); err != nil {
|
||||
return fmt.Errorf("exporting counter: %w", err)
|
||||
} else if sum, ok := agg.(aggregation.Sum); ok && instrumentKind.Monotonic() {
|
||||
if err := c.exportMonotonicCounter(ch, sum, numberKind, desc, labels); err != nil {
|
||||
return fmt.Errorf("exporting monotonic counter: %w", err)
|
||||
}
|
||||
} else if sum, ok := agg.(aggregation.Sum); ok && !instrumentKind.Monotonic() {
|
||||
if err := c.exportNonMonotonicCounter(ch, sum, numberKind, desc, labels); err != nil {
|
||||
return fmt.Errorf("exporting non monotonic counter: %w", err)
|
||||
}
|
||||
} else if lastValue, ok := agg.(aggregation.LastValue); ok {
|
||||
if err := c.exportLastValue(ch, lastValue, numberKind, desc, labels); err != nil {
|
||||
@ -267,7 +272,22 @@ func (c *collector) exportLastValue(ch chan<- prometheus.Metric, lvagg aggregati
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *collector) exportCounter(ch chan<- prometheus.Metric, sum aggregation.Sum, kind otel.NumberKind, desc *prometheus.Desc, labels []string) error {
|
||||
func (c *collector) exportNonMonotonicCounter(ch chan<- prometheus.Metric, sum aggregation.Sum, kind otel.NumberKind, desc *prometheus.Desc, labels []string) error {
|
||||
v, err := sum.Sum()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error retrieving counter: %w", err)
|
||||
}
|
||||
|
||||
m, err := prometheus.NewConstMetric(desc, prometheus.GaugeValue, v.CoerceToFloat64(kind), labels...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating constant metric: %w", err)
|
||||
}
|
||||
|
||||
ch <- m
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *collector) exportMonotonicCounter(ch chan<- prometheus.Metric, sum aggregation.Sum, kind otel.NumberKind, desc *prometheus.Desc, labels []string) error {
|
||||
v, err := sum.Sum()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error retrieving counter: %w", err)
|
||||
|
@ -34,6 +34,10 @@ import (
|
||||
)
|
||||
|
||||
func TestPrometheusExporter(t *testing.T) {
|
||||
// #TODO: This test does not adequately verify the type of
|
||||
// prometheus metric exported for all types - for example,
|
||||
// it does not verify that an UpDown- counter is exported
|
||||
// as a gauge. To be improved.
|
||||
exporter, err := prometheus.NewExportPipeline(
|
||||
prometheus.Config{
|
||||
DefaultHistogramBoundaries: []float64{-0.5, 1},
|
||||
@ -44,7 +48,7 @@ func TestPrometheusExporter(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
meter := exporter.MeterProvider().Meter("test")
|
||||
|
||||
upDownCounter := otel.Must(meter).NewFloat64UpDownCounter("updowncounter")
|
||||
counter := otel.Must(meter).NewFloat64Counter("counter")
|
||||
valuerecorder := otel.Must(meter).NewFloat64ValueRecorder("valuerecorder")
|
||||
|
||||
@ -61,6 +65,12 @@ func TestPrometheusExporter(t *testing.T) {
|
||||
|
||||
expected = append(expected, `counter{A="B",C="D",R="V"} 15.3`)
|
||||
|
||||
_ = otel.Must(meter).NewInt64ValueObserver("intobserver", func(_ context.Context, result otel.Int64ObserverResult) {
|
||||
result.Observe(1, labels...)
|
||||
})
|
||||
|
||||
expected = append(expected, `intobserver{A="B",C="D",R="V"} 1`)
|
||||
|
||||
valuerecorder.Record(ctx, -0.6, labels...)
|
||||
valuerecorder.Record(ctx, -0.4, labels...)
|
||||
valuerecorder.Record(ctx, 0.6, labels...)
|
||||
@ -72,6 +82,11 @@ func TestPrometheusExporter(t *testing.T) {
|
||||
expected = append(expected, `valuerecorder_count{A="B",C="D",R="V"} 4`)
|
||||
expected = append(expected, `valuerecorder_sum{A="B",C="D",R="V"} 19.6`)
|
||||
|
||||
upDownCounter.Add(ctx, 10, labels...)
|
||||
upDownCounter.Add(ctx, -3.2, labels...)
|
||||
|
||||
expected = append(expected, `updowncounter{A="B",C="D",R="V"} 6.8`)
|
||||
|
||||
compareExport(t, exporter, expected)
|
||||
compareExport(t, exporter, expected)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user