Skip to content
Closed
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

### Fixed

- Fix `go.opentelemetry.io/contrib/otelconf` Prometheus reader converting OTel dot-style label names (e.g. `service.name`) to underscore-style (`service_name`) in `target_info` when both `without_type_suffix` and `without_units` are set. Use `NoTranslation` instead of `UnderscoreEscapingWithoutSuffixes` to preserve dot-style label names while still suppressing metric name suffixes. (#PLACEHOLDER)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Fix `go.opentelemetry.io/contrib/otelconf` Prometheus reader converting OTel dot-style label names (e.g. `service.name`) to underscore-style (`service_name`) in `target_info` when both `without_type_suffix` and `without_units` are set. Use `NoTranslation` instead of `UnderscoreEscapingWithoutSuffixes` to preserve dot-style label names while still suppressing metric name suffixes. (#PLACEHOLDER)
- Fix `go.opentelemetry.io/contrib/otelconf` Prometheus reader converting OTel dot-style label names (e.g. `service.name`) to underscore-style (`service_name`) in `target_info` when both `without_type_suffix` and `without_units` are set. Use `NoTranslation` instead of `UnderscoreEscapingWithoutSuffixes` to preserve dot-style label names while still suppressing metric name suffixes. (#8696 )

- Limit the request body size at 1MB in `go.opentelemetry.io/contrib/zpages`. (#8656)

### Removed
Expand Down
6 changes: 5 additions & 1 deletion otelconf/v0.3.0/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,11 @@ func prometheusReaderOpts(prometheusConfig *Prometheus) ([]otelprom.Option, erro
}

if prometheusConfig.WithoutTypeSuffix != nil && *prometheusConfig.WithoutTypeSuffix && prometheusConfig.WithoutUnits != nil && *prometheusConfig.WithoutUnits {
opts = append(opts, otelprom.WithTranslationStrategy(otlptranslator.UnderscoreEscapingWithoutSuffixes))
// NoTranslation preserves OTel dot-style label names (e.g. service.name)
// and suppresses metric name suffixes. The exporter's newConfig will
// automatically set withoutCounterSuffixes and withoutUnits when
// ShouldAddSuffixes() is false.
opts = append(opts, otelprom.WithTranslationStrategy(otlptranslator.NoTranslation))
} else {
opts = append(opts, otelprom.WithTranslationStrategy(otlptranslator.NoUTF8EscapingWithSuffixes))
}
Expand Down
41 changes: 41 additions & 0 deletions otelconf/v0.3.0/metric_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1594,6 +1594,47 @@ func TestPrometheusReaderConfigurationOptions(t *testing.T) {
assert.Equal(t, http.StatusOK, resp.StatusCode)
}

// TestPrometheusReaderDotStyleLabels verifies that OTel dot-style resource
// attribute names (e.g. service.name) are preserved in target_info when both
// without_type_suffix and without_units are set which is default config for OTel Collector.
func TestPrometheusReaderDotStyleLabels(t *testing.T) {
host := "localhost"
port := 0
reader, err := prometheusReader(t.Context(), &Prometheus{
Host: &host,
Port: &port,
WithoutTypeSuffix: ptr(true),
WithoutUnits: ptr(true),
})
require.NoError(t, err)

res := resource.NewWithAttributes("", attribute.String("service.name", "test-svc"))
mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader), sdkmetric.WithResource(res))
t.Cleanup(func() {
//nolint:usetesting // required to avoid getting a canceled context at cleanup.
require.NoError(t, mp.Shutdown(context.Background()))
})
c, err := mp.Meter("test").Int64Counter("test.counter")
require.NoError(t, err)
c.Add(t.Context(), 1)

addr := reader.(readerWithServer).server.Addr
req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, "http://"+addr+"/metrics", http.NoBody)
require.NoError(t, err)
req.Header.Set("Accept", "application/openmetrics-text; version=1.0.0; escaping=allow-utf-8")
resp, err := http.DefaultClient.Do(req)
require.NoError(t, err)
defer resp.Body.Close()

var buf bytes.Buffer
_, err = buf.ReadFrom(resp.Body)
require.NoError(t, err)
body := buf.String()

Copy link
Copy Markdown
Member

@XSAM XSAM Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we verify the body contains target_info and not contains the target.info? This prevents MetricNamer accidentally takes TranslationStrategyOption.NoTranslation seriously in the future.

assert.Contains(t, body, `"service.name"="test-svc"`)
assert.NotContains(t, body, "service_name")
}

func Test_otlpGRPCMetricExporter(t *testing.T) {
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
// TODO (#8115): Fix the flakiness on Windows and MacOS.
Expand Down
Loading