From 905684c58a62fbfc0cbe3bc1a2a7d146275e8aa7 Mon Sep 17 00:00:00 2001 From: Damien Mathieu <42@dmathieu.com> Date: Thu, 27 Mar 2025 09:41:35 +0100 Subject: [PATCH] Ignore deprecation warnings about NameValidationScheme (#6449) In 0.63.0, prometheus deprecates the `model.NameValidationScheme` attribute. https://github.com/open-telemetry/opentelemetry-go/actions/runs/13885046847/job/38848614767?pr=6442 > Error: exporter_test.go:478:6: SA1019: model.NameValidationScheme is deprecated: This variable should not be used and might be removed in the far future. If you wish to stick to the legacy name validation use `IsValidLegacyMetricName()` and `LabelName.IsValidLegacy()` methods instead. This variable is here as an escape hatch for emergency cases, given the recent change from `LegacyValidation` to `UTF8Validation`, e.g., to delay UTF-8 migrations in time or aid in debugging unforeseen results of the change. In such a case, a temporary assignment to `LegacyValidation` value in the `init()` function in your main.go or so, could be considered. (staticcheck) We probably want to keep supporting this scheme in the near future though. So this ignores those deprecations, so we can upgrade the package. Unblocks https://github.com/open-telemetry/opentelemetry-go/pull/6442 --- CHANGELOG.md | 12 ++++++++++++ exporters/prometheus/config.go | 9 ++++++++- exporters/prometheus/exporter.go | 5 +++-- exporters/prometheus/exporter_test.go | 10 +++++----- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13a8e497d..15ffa7a72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +> [!WARNING] +> This is the last version to support `model.LegacyValidation` for +> `go.opentelemetry.io/otel/exporters/prometheus`. +> The next version (v0.59.0) will only support the default `model.UTF8Validation`. +> +> See also [Change default validation scheme to UTF8Validation](https://github.com/prometheus/common/pull/724) +> in the prometheus repository. + ### Added - The `go.opentelemetry.io/otel/semconv/v1.31.0` package. @@ -29,6 +37,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - `go.opentelemetry.io/otel/log/logtest` is now a separate Go module. (#6465) - `go.opentelemetry.io/otel/sdk/log/logtest` is now a separate Go module. (#6466) +### Deprecated + +- Deprecate support for `model.LegacyValidation` for `go.opentelemetry.io/otel/exporters/prometheus`. (#6449) + ### Fixes - Stop percent encoding header environment variables in `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc` and `go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp`. (#6392) diff --git a/exporters/prometheus/config.go b/exporters/prometheus/config.go index 660675dd6..a743b469d 100644 --- a/exporters/prometheus/config.go +++ b/exporters/prometheus/config.go @@ -5,11 +5,13 @@ package prometheus // import "go.opentelemetry.io/otel/exporters/prometheus" import ( "strings" + "sync" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/model" "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/internal/global" "go.opentelemetry.io/otel/sdk/metric" ) @@ -25,6 +27,10 @@ type config struct { resourceAttributesFilter attribute.Filter } +var logDeprecatedLegacyScheme = sync.OnceFunc(func() { + global.Warn("prometheus exporter legacy scheme deprecated: support for the legacy NameValidationScheme will be removed in the next release") +}) + // newConfig creates a validated config configured with options. func newConfig(opts ...Option) config { cfg := config{} @@ -132,7 +138,8 @@ func WithoutScopeInfo() Option { // have special behavior based on their name. func WithNamespace(ns string) Option { return optionFunc(func(cfg config) config { - if model.NameValidationScheme != model.UTF8Validation { + if model.NameValidationScheme != model.UTF8Validation { // nolint:staticcheck // We need this check to keep supporting the legacy scheme. + logDeprecatedLegacyScheme() // Only sanitize if prometheus does not support UTF-8. ns = model.EscapeName(ns, model.NameEscapingScheme) } diff --git a/exporters/prometheus/exporter.go b/exporters/prometheus/exporter.go index c5323c646..d4fd68d0c 100644 --- a/exporters/prometheus/exporter.go +++ b/exporters/prometheus/exporter.go @@ -327,7 +327,7 @@ func getAttrs(attrs attribute.Set) ([]string, []string) { values := make([]string, 0, attrs.Len()) itr := attrs.Iter() - if model.NameValidationScheme == model.UTF8Validation { + if model.NameValidationScheme == model.UTF8Validation { // nolint:staticcheck // We need this check to keep supporting the legacy scheme. // Do not perform sanitization if prometheus supports UTF-8. for itr.Next() { kv := itr.Attribute() @@ -413,8 +413,9 @@ var unitSuffixes = map[string]string{ // getName returns the sanitized name, prefixed with the namespace and suffixed with unit. func (c *collector) getName(m metricdata.Metrics, typ *dto.MetricType) string { name := m.Name - if model.NameValidationScheme != model.UTF8Validation { + if model.NameValidationScheme != model.UTF8Validation { // nolint:staticcheck // We need this check to keep supporting the legacy scheme. // Only sanitize if prometheus does not support UTF-8. + logDeprecatedLegacyScheme() name = model.EscapeName(name, model.NameEscapingScheme) } addCounterSuffix := !c.withoutCounterSuffixes && *typ == dto.MetricType_COUNTER diff --git a/exporters/prometheus/exporter_test.go b/exporters/prometheus/exporter_test.go index d75174586..ab625be81 100644 --- a/exporters/prometheus/exporter_test.go +++ b/exporters/prometheus/exporter_test.go @@ -472,10 +472,10 @@ func TestPrometheusExporter(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { if tc.disableUTF8 { - model.NameValidationScheme = model.LegacyValidation + model.NameValidationScheme = model.LegacyValidation // nolint:staticcheck // We need this check to keep supporting the legacy scheme. defer func() { // Reset to defaults - model.NameValidationScheme = model.UTF8Validation + model.NameValidationScheme = model.UTF8Validation // nolint:staticcheck // We need this check to keep supporting the legacy scheme. }() } ctx := context.Background() @@ -1029,13 +1029,13 @@ func TestExemplars(t *testing.T) { } { t.Run(tc.name, func(t *testing.T) { originalEscapingScheme := model.NameEscapingScheme - originalValidationScheme := model.NameValidationScheme + originalValidationScheme := model.NameValidationScheme // nolint:staticcheck // We need this check to keep supporting the legacy scheme. model.NameEscapingScheme = tc.escapingScheme - model.NameValidationScheme = tc.validationScheme + model.NameValidationScheme = tc.validationScheme // nolint:staticcheck // We need this check to keep supporting the legacy scheme. // Restore original value after the test is complete defer func() { model.NameEscapingScheme = originalEscapingScheme - model.NameValidationScheme = originalValidationScheme + model.NameValidationScheme = originalValidationScheme // nolint:staticcheck // We need this check to keep supporting the legacy scheme. }() // initialize registry exporter ctx := context.Background()