You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2026-06-03 18:35:08 +02:00
prometheus exporter ignores metrics from the Prometheus bridge (#7688)
Related to https://github.com/open-telemetry/opentelemetry-go/issues/7686. This makes the Prometheus exporter ignore all metrics from the Prometheus bridge. This is almost certainly a misconfiguration, but may happen when using autoexport or other packages that automatically install the bridge.
This commit is contained in:
@@ -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 -->
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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{
|
||||
@@ -96,6 +101,8 @@ type collector struct {
|
||||
unitNamer otlptranslator.UnitNamer
|
||||
|
||||
inst *observ.Instrumentation
|
||||
|
||||
bridgeErrorOnce sync.Once
|
||||
}
|
||||
|
||||
// New returns a Prometheus Exporter.
|
||||
@@ -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
|
||||
}
|
||||
n := len(c.resourceKeyVals.keys) + 2 // resource attrs + scope name + scope version
|
||||
kv := keyVals{
|
||||
keys: make([]string, 0, n),
|
||||
|
||||
@@ -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)
|
||||
|
||||
+3
@@ -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
|
||||
Reference in New Issue
Block a user