Skip to content

Commit

Permalink
Add WithoutCounterSuffixes option in go.opentelemetry.io/otel/exporte…
Browse files Browse the repository at this point in the history
…rs/prometheus to disable addition of _total suffixes (#4306)
  • Loading branch information
dashpole authored Jul 14, 2023
1 parent 55fb2bb commit 03b8c47
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Add `PeriodicReader` struct in `go.opentelemetry.io/otel/sdk/metric`. (#4244)
- Add `Exporter` struct in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc`. (#4272)
- Add `Exporter` struct in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp`. (#4272)
- Add `WithoutCounterSuffixes` option in `go.opentelemetry.io/otel/exporters/prometheus` to disable addition of `_total` suffixes. (#TODO)

### Changed

Expand Down
26 changes: 20 additions & 6 deletions exporters/prometheus/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ import (

// config contains options for the exporter.
type config struct {
registerer prometheus.Registerer
disableTargetInfo bool
withoutUnits bool
aggregation metric.AggregationSelector
disableScopeInfo bool
namespace string
registerer prometheus.Registerer
disableTargetInfo bool
withoutUnits bool
withoutCounterSuffixes bool
aggregation metric.AggregationSelector
disableScopeInfo bool
namespace string
}

// newConfig creates a validated config configured with options.
Expand Down Expand Up @@ -110,6 +111,19 @@ func WithoutUnits() Option {
})
}

// WithoutUnits disables exporter's addition _total suffixes on counters.
//
// By default, metric names include a _total suffix to follow Prometheus naming
// conventions. For example, the counter metric happy.people would become
// happy_people_total. With this option set, the name would instead be
// happy_people.
func WithoutCounterSuffixes() Option {
return optionFunc(func(cfg config) config {
cfg.withoutCounterSuffixes = true
return cfg
})
}

// WithoutScopeInfo configures the Exporter to not export the otel_scope_info metric.
// If not specified, the Exporter will create a otel_scope_info metric containing
// the metrics' Instrumentation Scope, and also add labels about Instrumentation Scope to all metric points.
Expand Down
28 changes: 15 additions & 13 deletions exporters/prometheus/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ var _ metric.Reader = &Exporter{}
type collector struct {
reader metric.Reader

withoutUnits bool
disableScopeInfo bool
namespace string
withoutUnits bool
withoutCounterSuffixes bool
disableScopeInfo bool
namespace string

mu sync.Mutex // mu protects all members below from the concurrent access.
disableTargetInfo bool
Expand All @@ -70,7 +71,7 @@ type collector struct {
metricFamilies map[string]*dto.MetricFamily
}

// prometheus counters MUST have a _total suffix:
// prometheus counters MUST have a _total suffix by default:
// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/compatibility/prometheus_and_openmetrics.md
const counterSuffix = "_total"

Expand All @@ -84,13 +85,14 @@ func New(opts ...Option) (*Exporter, error) {
reader := metric.NewManualReader(cfg.manualReaderOptions()...)

collector := &collector{
reader: reader,
disableTargetInfo: cfg.disableTargetInfo,
withoutUnits: cfg.withoutUnits,
disableScopeInfo: cfg.disableScopeInfo,
scopeInfos: make(map[instrumentation.Scope]prometheus.Metric),
metricFamilies: make(map[string]*dto.MetricFamily),
namespace: cfg.namespace,
reader: reader,
disableTargetInfo: cfg.disableTargetInfo,
withoutUnits: cfg.withoutUnits,
withoutCounterSuffixes: cfg.withoutCounterSuffixes,
disableScopeInfo: cfg.disableScopeInfo,
scopeInfos: make(map[instrumentation.Scope]prometheus.Metric),
metricFamilies: make(map[string]*dto.MetricFamily),
namespace: cfg.namespace,
}

if err := cfg.registerer.Register(collector); err != nil {
Expand Down Expand Up @@ -387,12 +389,12 @@ func (c *collector) metricTypeAndName(m metricdata.Metrics) (*dto.MetricType, st
case metricdata.Histogram[int64], metricdata.Histogram[float64]:
return dto.MetricType_HISTOGRAM.Enum(), name
case metricdata.Sum[float64]:
if v.IsMonotonic {
if v.IsMonotonic && !c.withoutCounterSuffixes {
return dto.MetricType_COUNTER.Enum(), name + counterSuffix
}
return dto.MetricType_GAUGE.Enum(), name
case metricdata.Sum[int64]:
if v.IsMonotonic {
if v.IsMonotonic && !c.withoutCounterSuffixes {
return dto.MetricType_COUNTER.Enum(), name + counterSuffix
}
return dto.MetricType_GAUGE.Enum(), name
Expand Down
30 changes: 30 additions & 0 deletions exporters/prometheus/exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,36 @@ func TestPrometheusExporter(t *testing.T) {
counter.Add(ctx, 5, otelmetric.WithAttributeSet(attrs2))
},
},
{
name: "counter with suffixes disabled",
expectedFile: "testdata/counter_disabled_suffix.txt",
options: []Option{WithoutCounterSuffixes()},
recordMetrics: func(ctx context.Context, meter otelmetric.Meter) {
opt := otelmetric.WithAttributes(
attribute.Key("A").String("B"),
attribute.Key("C").String("D"),
attribute.Key("E").Bool(true),
attribute.Key("F").Int(42),
)
counter, err := meter.Float64Counter(
"foo",
otelmetric.WithDescription("a simple counter without a total suffix"),
otelmetric.WithUnit("ms"),
)
require.NoError(t, err)
counter.Add(ctx, 5, opt)
counter.Add(ctx, 10.3, opt)
counter.Add(ctx, 9, opt)

attrs2 := attribute.NewSet(
attribute.Key("A").String("D"),
attribute.Key("C").String("B"),
attribute.Key("E").Bool(true),
attribute.Key("F").Int(42),
)
counter.Add(ctx, 5, otelmetric.WithAttributeSet(attrs2))
},
},
{
name: "gauge",
expectedFile: "testdata/gauge.txt",
Expand Down
10 changes: 10 additions & 0 deletions exporters/prometheus/testdata/counter_disabled_suffix.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# HELP foo_milliseconds a simple counter without a total suffix
# TYPE foo_milliseconds counter
foo_milliseconds{A="B",C="D",E="true",F="42",otel_scope_name="testmeter",otel_scope_version="v0.1.0"} 24.3
foo_milliseconds{A="D",C="B",E="true",F="42",otel_scope_name="testmeter",otel_scope_version="v0.1.0"} 5
# HELP otel_scope_info Instrumentation Scope metadata
# TYPE otel_scope_info gauge
otel_scope_info{otel_scope_name="testmeter",otel_scope_version="v0.1.0"} 1
# HELP target_info Target metadata
# TYPE target_info gauge
target_info{service_name="prometheus_test",telemetry_sdk_language="go",telemetry_sdk_name="opentelemetry",telemetry_sdk_version="latest"} 1

0 comments on commit 03b8c47

Please sign in to comment.