1
0
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:
Tawhid Hannan 2020-11-09 21:52:05 +00:00 committed by GitHub
parent 757030dc78
commit b7508da6fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 5 deletions

View File

@ -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

View File

@ -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)

View File

@ -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)
}