mirror of
https://github.com/prometheus/prometheus.git
synced 2025-11-04 18:31:35 +01:00
Merge branch 'release-3.7' into krajo/merge-release-3071-to-main
This commit is contained in:
commit
ea398c15e8
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## main / unreleased
|
## main / unreleased
|
||||||
|
|
||||||
|
## 3.7.1 / 2025-10-16
|
||||||
|
|
||||||
|
* [BUGFIX] OTLP: Prefix `key_` to label name when translating an OTel attribute name starting with a single underscore, and keep multiple consecutive underscores in label name when translating an OTel attribute name. This reverts the breaking changes introduced in 3.7.0. #17344
|
||||||
|
|
||||||
## 3.7.0 / 2025-10-15
|
## 3.7.0 / 2025-10-15
|
||||||
|
|
||||||
* [CHANGE] Remote-write: the following metrics are deprecated:
|
* [CHANGE] Remote-write: the following metrics are deprecated:
|
||||||
|
|||||||
@ -88,7 +88,11 @@ func (c *PrometheusConverter) createAttributes(resource pcommon.Resource, attrib
|
|||||||
c.scratchBuilder.Sort()
|
c.scratchBuilder.Sort()
|
||||||
sortedLabels := c.scratchBuilder.Labels()
|
sortedLabels := c.scratchBuilder.Labels()
|
||||||
|
|
||||||
labelNamer := otlptranslator.LabelNamer{UTF8Allowed: settings.AllowUTF8}
|
labelNamer := otlptranslator.LabelNamer{
|
||||||
|
UTF8Allowed: settings.AllowUTF8,
|
||||||
|
UnderscoreLabelSanitization: settings.LabelNameUnderscoreSanitization,
|
||||||
|
PreserveMultipleUnderscores: settings.LabelNamePreserveMultipleUnderscores,
|
||||||
|
}
|
||||||
|
|
||||||
if settings.AllowUTF8 {
|
if settings.AllowUTF8 {
|
||||||
// UTF8 is allowed, so conflicts aren't possible.
|
// UTF8 is allowed, so conflicts aren't possible.
|
||||||
@ -118,7 +122,7 @@ func (c *PrometheusConverter) createAttributes(resource pcommon.Resource, attrib
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := settings.PromoteResourceAttributes.addPromotedAttributes(c.builder, resourceAttrs, settings.AllowUTF8)
|
err := settings.PromoteResourceAttributes.addPromotedAttributes(c.builder, resourceAttrs, labelNamer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return labels.EmptyLabels(), err
|
return labels.EmptyLabels(), err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -67,14 +67,34 @@ func TestCreateAttributes(t *testing.T) {
|
|||||||
attrs.PutStr("metric-attr", "metric value")
|
attrs.PutStr("metric-attr", "metric value")
|
||||||
attrs.PutStr("metric-attr-other", "metric value other")
|
attrs.PutStr("metric-attr-other", "metric value other")
|
||||||
|
|
||||||
|
// Setup resources with underscores for sanitization tests
|
||||||
|
resourceAttrsWithUnderscores := map[string]string{
|
||||||
|
"service.name": "service name",
|
||||||
|
"service.instance.id": "service ID",
|
||||||
|
"_private": "private value",
|
||||||
|
"__reserved__": "reserved value",
|
||||||
|
"label___multi": "multi value",
|
||||||
|
}
|
||||||
|
resourceWithUnderscores := pcommon.NewResource()
|
||||||
|
for k, v := range resourceAttrsWithUnderscores {
|
||||||
|
resourceWithUnderscores.Attributes().PutStr(k, v)
|
||||||
|
}
|
||||||
|
attrsWithUnderscores := pcommon.NewMap()
|
||||||
|
attrsWithUnderscores.PutStr("_metric_private", "private metric")
|
||||||
|
attrsWithUnderscores.PutStr("metric___multi", "multi metric")
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
|
resource pcommon.Resource
|
||||||
|
attrs pcommon.Map
|
||||||
scope scope
|
scope scope
|
||||||
promoteAllResourceAttributes bool
|
promoteAllResourceAttributes bool
|
||||||
promoteResourceAttributes []string
|
promoteResourceAttributes []string
|
||||||
promoteScope bool
|
promoteScope bool
|
||||||
ignoreResourceAttributes []string
|
ignoreResourceAttributes []string
|
||||||
ignoreAttrs []string
|
ignoreAttrs []string
|
||||||
|
labelNameUnderscoreLabelSanitization bool
|
||||||
|
labelNamePreserveMultipleUnderscores bool
|
||||||
expectedLabels labels.Labels
|
expectedLabels labels.Labels
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@ -251,6 +271,121 @@ func TestCreateAttributes(t *testing.T) {
|
|||||||
"otel_scope_attr2", "value2",
|
"otel_scope_attr2", "value2",
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
// Label sanitization test cases
|
||||||
|
{
|
||||||
|
name: "Underscore sanitization enabled - prepends key_ to labels starting with single _",
|
||||||
|
resource: resourceWithUnderscores,
|
||||||
|
attrs: attrsWithUnderscores,
|
||||||
|
promoteResourceAttributes: []string{"_private"},
|
||||||
|
labelNameUnderscoreLabelSanitization: true,
|
||||||
|
labelNamePreserveMultipleUnderscores: true,
|
||||||
|
expectedLabels: labels.FromStrings(
|
||||||
|
"__name__", "test_metric",
|
||||||
|
"instance", "service ID",
|
||||||
|
"job", "service name",
|
||||||
|
"key_private", "private value",
|
||||||
|
"key_metric_private", "private metric",
|
||||||
|
"metric___multi", "multi metric",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Underscore sanitization disabled - keeps labels with _ as-is",
|
||||||
|
resource: resourceWithUnderscores,
|
||||||
|
attrs: attrsWithUnderscores,
|
||||||
|
promoteResourceAttributes: []string{"_private"},
|
||||||
|
labelNameUnderscoreLabelSanitization: false,
|
||||||
|
labelNamePreserveMultipleUnderscores: true,
|
||||||
|
expectedLabels: labels.FromStrings(
|
||||||
|
"__name__", "test_metric",
|
||||||
|
"instance", "service ID",
|
||||||
|
"job", "service name",
|
||||||
|
"_private", "private value",
|
||||||
|
"_metric_private", "private metric",
|
||||||
|
"metric___multi", "multi metric",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Multiple underscores preserved - keeps consecutive underscores",
|
||||||
|
resource: resourceWithUnderscores,
|
||||||
|
attrs: attrsWithUnderscores,
|
||||||
|
promoteResourceAttributes: []string{"label___multi"},
|
||||||
|
labelNameUnderscoreLabelSanitization: false,
|
||||||
|
labelNamePreserveMultipleUnderscores: true,
|
||||||
|
expectedLabels: labels.FromStrings(
|
||||||
|
"__name__", "test_metric",
|
||||||
|
"instance", "service ID",
|
||||||
|
"job", "service name",
|
||||||
|
"label___multi", "multi value",
|
||||||
|
"_metric_private", "private metric",
|
||||||
|
"metric___multi", "multi metric",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Multiple underscores collapsed - collapses to single underscore",
|
||||||
|
resource: resourceWithUnderscores,
|
||||||
|
attrs: attrsWithUnderscores,
|
||||||
|
promoteResourceAttributes: []string{"label___multi"},
|
||||||
|
labelNameUnderscoreLabelSanitization: false,
|
||||||
|
labelNamePreserveMultipleUnderscores: false,
|
||||||
|
expectedLabels: labels.FromStrings(
|
||||||
|
"__name__", "test_metric",
|
||||||
|
"instance", "service ID",
|
||||||
|
"job", "service name",
|
||||||
|
"label_multi", "multi value",
|
||||||
|
"_metric_private", "private metric",
|
||||||
|
"metric_multi", "multi metric",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Both sanitization options enabled",
|
||||||
|
resource: resourceWithUnderscores,
|
||||||
|
attrs: attrsWithUnderscores,
|
||||||
|
promoteResourceAttributes: []string{"_private", "label___multi"},
|
||||||
|
labelNameUnderscoreLabelSanitization: true,
|
||||||
|
labelNamePreserveMultipleUnderscores: true,
|
||||||
|
expectedLabels: labels.FromStrings(
|
||||||
|
"__name__", "test_metric",
|
||||||
|
"instance", "service ID",
|
||||||
|
"job", "service name",
|
||||||
|
"key_private", "private value",
|
||||||
|
"label___multi", "multi value",
|
||||||
|
"key_metric_private", "private metric",
|
||||||
|
"metric___multi", "multi metric",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Both sanitization options disabled",
|
||||||
|
resource: resourceWithUnderscores,
|
||||||
|
attrs: attrsWithUnderscores,
|
||||||
|
promoteResourceAttributes: []string{"_private", "label___multi"},
|
||||||
|
labelNameUnderscoreLabelSanitization: false,
|
||||||
|
labelNamePreserveMultipleUnderscores: false,
|
||||||
|
expectedLabels: labels.FromStrings(
|
||||||
|
"__name__", "test_metric",
|
||||||
|
"instance", "service ID",
|
||||||
|
"job", "service name",
|
||||||
|
"_private", "private value",
|
||||||
|
"label_multi", "multi value",
|
||||||
|
"_metric_private", "private metric",
|
||||||
|
"metric_multi", "multi metric",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Reserved labels (starting with __) are never modified",
|
||||||
|
resource: resourceWithUnderscores,
|
||||||
|
attrs: attrsWithUnderscores,
|
||||||
|
promoteResourceAttributes: []string{"__reserved__"},
|
||||||
|
labelNameUnderscoreLabelSanitization: true,
|
||||||
|
labelNamePreserveMultipleUnderscores: false,
|
||||||
|
expectedLabels: labels.FromStrings(
|
||||||
|
"__name__", "test_metric",
|
||||||
|
"instance", "service ID",
|
||||||
|
"job", "service name",
|
||||||
|
"__reserved__", "reserved value",
|
||||||
|
"key_metric_private", "private metric",
|
||||||
|
"metric_multi", "multi metric",
|
||||||
|
),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
@ -262,8 +397,23 @@ func TestCreateAttributes(t *testing.T) {
|
|||||||
IgnoreResourceAttributes: tc.ignoreResourceAttributes,
|
IgnoreResourceAttributes: tc.ignoreResourceAttributes,
|
||||||
}),
|
}),
|
||||||
PromoteScopeMetadata: tc.promoteScope,
|
PromoteScopeMetadata: tc.promoteScope,
|
||||||
|
LabelNameUnderscoreSanitization: tc.labelNameUnderscoreLabelSanitization,
|
||||||
|
LabelNamePreserveMultipleUnderscores: tc.labelNamePreserveMultipleUnderscores,
|
||||||
}
|
}
|
||||||
lbls, err := c.createAttributes(resource, attrs, tc.scope, settings, tc.ignoreAttrs, false, Metadata{}, model.MetricNameLabel, "test_metric")
|
// Use test case specific resource/attrs if provided, otherwise use defaults
|
||||||
|
// Check if tc.resource is initialized (non-zero) by trying to get its attributes
|
||||||
|
testResource := resource
|
||||||
|
testAttrs := attrs
|
||||||
|
// For pcommon types, we can check if they're non-zero by seeing if they have attributes
|
||||||
|
// Since zero-initialized Resource is not valid, we use a simple heuristic:
|
||||||
|
// if the struct has been explicitly set in the test case, use it
|
||||||
|
if tc.resource != (pcommon.Resource{}) {
|
||||||
|
testResource = tc.resource
|
||||||
|
}
|
||||||
|
if tc.attrs != (pcommon.Map{}) {
|
||||||
|
testAttrs = tc.attrs
|
||||||
|
}
|
||||||
|
lbls, err := c.createAttributes(testResource, testAttrs, tc.scope, settings, tc.ignoreAttrs, false, Metadata{}, model.MetricNameLabel, "test_metric")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
testutil.RequireEqual(t, lbls, tc.expectedLabels)
|
testutil.RequireEqual(t, lbls, tc.expectedLabels)
|
||||||
|
|||||||
@ -54,6 +54,12 @@ type Settings struct {
|
|||||||
// PromoteScopeMetadata controls whether to promote OTel scope metadata to metric labels.
|
// PromoteScopeMetadata controls whether to promote OTel scope metadata to metric labels.
|
||||||
PromoteScopeMetadata bool
|
PromoteScopeMetadata bool
|
||||||
EnableTypeAndUnitLabels bool
|
EnableTypeAndUnitLabels bool
|
||||||
|
// LabelNameUnderscoreSanitization controls whether to enable prepending of 'key' to labels
|
||||||
|
// starting with '_'. Reserved labels starting with `__` are not modified.
|
||||||
|
LabelNameUnderscoreSanitization bool
|
||||||
|
// LabelNamePreserveMultipleUnderscores enables preserving of multiple
|
||||||
|
// consecutive underscores in label names when AllowUTF8 is false.
|
||||||
|
LabelNamePreserveMultipleUnderscores bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrometheusConverter converts from OTel write format to Prometheus remote write format.
|
// PrometheusConverter converts from OTel write format to Prometheus remote write format.
|
||||||
@ -305,12 +311,11 @@ func NewPromoteResourceAttributes(otlpCfg config.OTLPConfig) *PromoteResourceAtt
|
|||||||
}
|
}
|
||||||
|
|
||||||
// addPromotedAttributes adds labels for promoted resourceAttributes to the builder.
|
// addPromotedAttributes adds labels for promoted resourceAttributes to the builder.
|
||||||
func (s *PromoteResourceAttributes) addPromotedAttributes(builder *labels.Builder, resourceAttributes pcommon.Map, allowUTF8 bool) error {
|
func (s *PromoteResourceAttributes) addPromotedAttributes(builder *labels.Builder, resourceAttributes pcommon.Map, labelNamer otlptranslator.LabelNamer) error {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
labelNamer := otlptranslator.LabelNamer{UTF8Allowed: allowUTF8}
|
|
||||||
if s.promoteAll {
|
if s.promoteAll {
|
||||||
var err error
|
var err error
|
||||||
resourceAttributes.Range(func(name string, value pcommon.Value) bool {
|
resourceAttributes.Range(func(name string, value pcommon.Value) bool {
|
||||||
|
|||||||
@ -680,6 +680,10 @@ func (rw *rwExporter) ConsumeMetrics(ctx context.Context, md pmetric.Metrics) er
|
|||||||
AllowDeltaTemporality: rw.allowDeltaTemporality,
|
AllowDeltaTemporality: rw.allowDeltaTemporality,
|
||||||
LookbackDelta: rw.lookbackDelta,
|
LookbackDelta: rw.lookbackDelta,
|
||||||
EnableTypeAndUnitLabels: rw.enableTypeAndUnitLabels,
|
EnableTypeAndUnitLabels: rw.enableTypeAndUnitLabels,
|
||||||
|
// For backwards compatibility.
|
||||||
|
LabelNameUnderscoreSanitization: true,
|
||||||
|
// For backwards compatibility.
|
||||||
|
LabelNamePreserveMultipleUnderscores: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@prometheus-io/mantine-ui",
|
"name": "@prometheus-io/mantine-ui",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.307.0",
|
"version": "0.307.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "vite",
|
"start": "vite",
|
||||||
@ -28,7 +28,7 @@
|
|||||||
"@microsoft/fetch-event-source": "^2.0.1",
|
"@microsoft/fetch-event-source": "^2.0.1",
|
||||||
"@nexucis/fuzzy": "^0.5.1",
|
"@nexucis/fuzzy": "^0.5.1",
|
||||||
"@nexucis/kvsearch": "^0.9.1",
|
"@nexucis/kvsearch": "^0.9.1",
|
||||||
"@prometheus-io/codemirror-promql": "0.307.0",
|
"@prometheus-io/codemirror-promql": "0.307.1",
|
||||||
"@reduxjs/toolkit": "^2.9.0",
|
"@reduxjs/toolkit": "^2.9.0",
|
||||||
"@tabler/icons-react": "^3.35.0",
|
"@tabler/icons-react": "^3.35.0",
|
||||||
"@tanstack/react-query": "^5.90.2",
|
"@tanstack/react-query": "^5.90.2",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@prometheus-io/codemirror-promql",
|
"name": "@prometheus-io/codemirror-promql",
|
||||||
"version": "0.307.0",
|
"version": "0.307.1",
|
||||||
"description": "a CodeMirror mode for the PromQL language",
|
"description": "a CodeMirror mode for the PromQL language",
|
||||||
"types": "dist/esm/index.d.ts",
|
"types": "dist/esm/index.d.ts",
|
||||||
"module": "dist/esm/index.js",
|
"module": "dist/esm/index.js",
|
||||||
@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/prometheus/prometheus/blob/main/web/ui/module/codemirror-promql/README.md",
|
"homepage": "https://github.com/prometheus/prometheus/blob/main/web/ui/module/codemirror-promql/README.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prometheus-io/lezer-promql": "0.307.0",
|
"@prometheus-io/lezer-promql": "0.307.1",
|
||||||
"lru-cache": "^11.2.2"
|
"lru-cache": "^11.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@prometheus-io/lezer-promql",
|
"name": "@prometheus-io/lezer-promql",
|
||||||
"version": "0.307.0",
|
"version": "0.307.1",
|
||||||
"description": "lezer-based PromQL grammar",
|
"description": "lezer-based PromQL grammar",
|
||||||
"main": "dist/index.cjs",
|
"main": "dist/index.cjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
14
web/ui/package-lock.json
generated
14
web/ui/package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "prometheus-io",
|
"name": "prometheus-io",
|
||||||
"version": "0.307.0",
|
"version": "0.307.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "prometheus-io",
|
"name": "prometheus-io",
|
||||||
"version": "0.307.0",
|
"version": "0.307.1",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"mantine-ui",
|
"mantine-ui",
|
||||||
"module/*"
|
"module/*"
|
||||||
@ -24,7 +24,7 @@
|
|||||||
},
|
},
|
||||||
"mantine-ui": {
|
"mantine-ui": {
|
||||||
"name": "@prometheus-io/mantine-ui",
|
"name": "@prometheus-io/mantine-ui",
|
||||||
"version": "0.307.0",
|
"version": "0.307.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.19.0",
|
"@codemirror/autocomplete": "^6.19.0",
|
||||||
"@codemirror/language": "^6.11.3",
|
"@codemirror/language": "^6.11.3",
|
||||||
@ -42,7 +42,7 @@
|
|||||||
"@microsoft/fetch-event-source": "^2.0.1",
|
"@microsoft/fetch-event-source": "^2.0.1",
|
||||||
"@nexucis/fuzzy": "^0.5.1",
|
"@nexucis/fuzzy": "^0.5.1",
|
||||||
"@nexucis/kvsearch": "^0.9.1",
|
"@nexucis/kvsearch": "^0.9.1",
|
||||||
"@prometheus-io/codemirror-promql": "0.307.0",
|
"@prometheus-io/codemirror-promql": "0.307.1",
|
||||||
"@reduxjs/toolkit": "^2.9.0",
|
"@reduxjs/toolkit": "^2.9.0",
|
||||||
"@tabler/icons-react": "^3.35.0",
|
"@tabler/icons-react": "^3.35.0",
|
||||||
"@tanstack/react-query": "^5.90.2",
|
"@tanstack/react-query": "^5.90.2",
|
||||||
@ -87,10 +87,10 @@
|
|||||||
},
|
},
|
||||||
"module/codemirror-promql": {
|
"module/codemirror-promql": {
|
||||||
"name": "@prometheus-io/codemirror-promql",
|
"name": "@prometheus-io/codemirror-promql",
|
||||||
"version": "0.307.0",
|
"version": "0.307.1",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prometheus-io/lezer-promql": "0.307.0",
|
"@prometheus-io/lezer-promql": "0.307.1",
|
||||||
"lru-cache": "^11.2.2"
|
"lru-cache": "^11.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -120,7 +120,7 @@
|
|||||||
},
|
},
|
||||||
"module/lezer-promql": {
|
"module/lezer-promql": {
|
||||||
"name": "@prometheus-io/lezer-promql",
|
"name": "@prometheus-io/lezer-promql",
|
||||||
"version": "0.307.0",
|
"version": "0.307.1",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@lezer/generator": "^1.8.0",
|
"@lezer/generator": "^1.8.0",
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "prometheus-io",
|
"name": "prometheus-io",
|
||||||
"description": "Monorepo for the Prometheus UI",
|
"description": "Monorepo for the Prometheus UI",
|
||||||
"version": "0.307.0",
|
"version": "0.307.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "bash build_ui.sh --all",
|
"build": "bash build_ui.sh --all",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user