Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

## [Unreleased]

### Changed

- `Exporter` in `go.opentelemetry.io/otel/exporter/prometheus` ignores metrics with the scope `go.opentelemetry.io/contrib/bridges/prometheus`.
This prevents scrape failures when the Prometheus exporter is misconfigured to get data from the Prometheus bridge. (#7688)

<!-- Released section -->
<!-- Don't change this section unless doing release -->

Expand Down
4 changes: 4 additions & 0 deletions exporters/prometheus/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@
// Package prometheus provides a Prometheus Exporter that converts
// OTLP metrics into the Prometheus exposition format and implements
// prometheus.Collector to provide a handler for these metrics.
//
// The Prometheus exporter ignores metrics from the Prometheus bridge. To
// export these metrics, simply register them directly with the Prometheus
// Handler.
package prometheus // import "go.opentelemetry.io/otel/exporters/prometheus"
9 changes: 6 additions & 3 deletions exporters/prometheus/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import "errors"

// Sentinel errors for consistent error checks in tests.
var (
errInvalidMetricType = errors.New("invalid metric type")
errInvalidMetric = errors.New("invalid metric")
errEHScaleBelowMin = errors.New("exponential histogram scale below minimum supported")
errInvalidMetricType = errors.New("invalid metric type")
errInvalidMetric = errors.New("invalid metric")
errEHScaleBelowMin = errors.New("exponential histogram scale below minimum supported")
errBridgeNotSupported = errors.New(
"metrics from the prometheus bridge are not supported in the prometheus exporter, and will be dropped",
)
)
13 changes: 13 additions & 0 deletions exporters/prometheus/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ const (
scopeNameLabel = scopeLabelPrefix + "name"
scopeVersionLabel = scopeLabelPrefix + "version"
scopeSchemaLabel = scopeLabelPrefix + "schema_url"
// metrics from the prometehus bridge are ignored because this produces
// errors. Users should directly register prometheus metrics with the
// Registerer, rather than round-tripping them through the bridge and
// exporter.
bridgeScopeName = "go.opentelemetry.io/contrib/bridges/prometheus"
)

var metricsPool = sync.Pool{
Expand Down Expand Up @@ -96,6 +101,8 @@ type collector struct {
unitNamer otlptranslator.UnitNamer

inst *observ.Instrumentation

bridgeErrorOnce sync.Once
}

// New returns a Prometheus Exporter.
Expand Down Expand Up @@ -229,6 +236,12 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) {
}

for j, scopeMetrics := range metrics.ScopeMetrics {
if scopeMetrics.Scope.Name == bridgeScopeName {
c.bridgeErrorOnce.Do(func() {
otel.Handle(errBridgeNotSupported)
})
continue
Comment thread
dashpole marked this conversation as resolved.
}
n := len(c.resourceKeyVals.keys) + 2 // resource attrs + scope name + scope version
kv := keyVals{
keys: make([]string, 0, n),
Expand Down
45 changes: 45 additions & 0 deletions exporters/prometheus/exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,51 @@ func TestMultiScopes(t *testing.T) {
require.NoError(t, err)
}

func TestBridgeScopeIgnored(t *testing.T) {
var handledError error
eh := otel.ErrorHandlerFunc(func(e error) { handledError = errors.Join(handledError, e) })
otel.SetErrorHandler(eh)
ctx := t.Context()
registry := prometheus.NewRegistry()
exporter, err := New(
WithTranslationStrategy(otlptranslator.UnderscoreEscapingWithSuffixes),
WithRegisterer(registry),
)
require.NoError(t, err)

res, err := resource.New(ctx,
// always specify service.name because the default depends on the running OS
resource.WithAttributes(semconv.ServiceName("prometheus_test")),
// Overwrite the semconv.TelemetrySDKVersionKey value so we don't need to update every version
resource.WithAttributes(semconv.TelemetrySDKVersion("latest")),
)
require.NoError(t, err)
res, err = resource.Merge(resource.Default(), res)
require.NoError(t, err)

provider := metric.NewMeterProvider(
metric.WithReader(exporter),
metric.WithResource(res),
)

fooCounter, err := provider.Meter(bridgeScopeName, otelmetric.WithInstrumentationVersion("v0.1.0")).
Int64Counter(
"foo",
otelmetric.WithUnit("s"),
otelmetric.WithDescription("meter foo counter"))
assert.NoError(t, err)
fooCounter.Add(ctx, 100, otelmetric.WithAttributes(attribute.String("type", "foo")))

file, err := os.Open("testdata/just_target_info.txt")
require.NoError(t, err)
t.Cleanup(func() { require.NoError(t, file.Close()) })

err = testutil.GatherAndCompare(registry, file)
require.NoError(t, err)

require.ErrorIs(t, handledError, errBridgeNotSupported)
}

func TestDuplicateMetrics(t *testing.T) {
ab := attribute.NewSet(attribute.String("A", "B"))
withAB := otelmetric.WithAttributeSet(ab)
Expand Down
3 changes: 3 additions & 0 deletions exporters/prometheus/testdata/just_target_info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# 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