Skip to content

Commit 1af0f49

Browse files
authored
[chore] prom translation rw2 add support for metadata (#40469)
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description Adds support for translation of OTEL metadata to prometheus metadata in the RW2 translation path. <!-- Issue number (e.g. #1234) or full URL to issue, if applicable. --> #### Link to tracking issue Fixes Partially implements #33661 (when merging PR please don't close the tracing issue) <!--Describe what testing was performed and which tests were added.--> #### Testing * [x] Updated existing unit tests * [x] Added new ones * [x] e2e run with prometheus When debugging prometheus locally I can see it receives the metadata, but I can't see it in the frontend, because at least in prometheus metadata is not stored when coming via remote write for now ([source](https://github.com/jmichalek132/prometheus/blob/de23a9667cc670b26d8afdba8e3fa48a00e74ec0/storage/remote/write.go#L332)). ![image](https://github.com/user-attachments/assets/09781972-425f-45b1-9595-32d267da49cd) <!--Please delete paragraphs that you did not use before submitting.-->
1 parent 57ec471 commit 1af0f49

8 files changed

+279
-14
lines changed

pkg/translator/prometheusremotewrite/metrics_to_prw_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ func createExportRequest(resourceAttributeCount int, histogramCount int, nonHist
119119
for i := 1; i <= nonHistogramCount; i++ {
120120
m := metrics.AppendEmpty()
121121
m.SetEmptySum()
122+
m.SetDescription("test sum description")
123+
m.SetUnit("By")
122124
m.SetName(fmt.Sprintf("sum-%v", i))
123125
m.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative)
124126
point := m.Sum().DataPoints().AppendEmpty()
@@ -131,6 +133,8 @@ func createExportRequest(resourceAttributeCount int, histogramCount int, nonHist
131133
for i := 1; i <= nonHistogramCount; i++ {
132134
m := metrics.AppendEmpty()
133135
m.SetEmptyGauge()
136+
m.SetDescription("test gauge description")
137+
m.SetUnit("By")
134138
m.SetName(fmt.Sprintf("gauge-%v", i))
135139
point := m.Gauge().DataPoints().AppendEmpty()
136140
point.SetTimestamp(timestamp)

pkg/translator/prometheusremotewrite/metrics_to_prw_v2.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ type prometheusConverterV2 struct {
3838
symbolTable writev2.SymbolsTable
3939
}
4040

41+
type metadata struct {
42+
Type writev2.Metadata_MetricType
43+
Help string
44+
Unit string
45+
}
46+
4147
func newPrometheusConverterV2() *prometheusConverterV2 {
4248
return &prometheusConverterV2{
4349
unique: map[uint64]*writev2.TimeSeries{},
@@ -69,6 +75,11 @@ func (c *prometheusConverterV2) fromMetrics(md pmetric.Metrics, settings Setting
6975
}
7076

7177
promName := prometheustranslator.BuildCompliantName(metric, settings.Namespace, settings.AddMetricSuffixes)
78+
m := metadata{
79+
Type: otelMetricTypeToPromMetricTypeV2(metric),
80+
Help: metric.Description(),
81+
Unit: prometheustranslator.BuildCompliantPrometheusUnit(metric.Unit()),
82+
}
7283

7384
// handle individual metrics based on type
7485
//exhaustive:enforce
@@ -78,16 +89,16 @@ func (c *prometheusConverterV2) fromMetrics(md pmetric.Metrics, settings Setting
7889
if dataPoints.Len() == 0 {
7990
break
8091
}
81-
c.addGaugeNumberDataPoints(dataPoints, resource, settings, promName)
92+
c.addGaugeNumberDataPoints(dataPoints, resource, settings, promName, m)
8293
case pmetric.MetricTypeSum:
8394
dataPoints := metric.Sum().DataPoints()
8495
if dataPoints.Len() == 0 {
8596
break
8697
}
8798
if !metric.Sum().IsMonotonic() {
88-
c.addGaugeNumberDataPoints(dataPoints, resource, settings, promName)
99+
c.addGaugeNumberDataPoints(dataPoints, resource, settings, promName, m)
89100
} else {
90-
c.addSumNumberDataPoints(dataPoints, resource, metric, settings, promName)
101+
c.addSumNumberDataPoints(dataPoints, resource, metric, settings, promName, m)
91102
}
92103
case pmetric.MetricTypeHistogram:
93104
// TODO implement
@@ -116,7 +127,8 @@ func (c *prometheusConverterV2) timeSeries() []writev2.TimeSeries {
116127
return allTS
117128
}
118129

119-
func (c *prometheusConverterV2) addSample(sample *writev2.Sample, lbls []prompb.Label) {
130+
func (c *prometheusConverterV2) addSample(sample *writev2.Sample, lbls []prompb.Label, metadata metadata) {
131+
// TODO consider how to accommodate metadata in the symbol table when allocating the buffer, given not all metrics might have metadata.
120132
buf := make([]uint32, 0, len(lbls)*2)
121133

122134
// TODO: Read the PRW spec to see if labels need to be sorted. If it is, then we need to sort in export code. If not, we can sort in the test. (@dashpole have more context on this)
@@ -134,6 +146,11 @@ func (c *prometheusConverterV2) addSample(sample *writev2.Sample, lbls []prompb.
134146
ts := writev2.TimeSeries{
135147
LabelsRefs: buf,
136148
Samples: []writev2.Sample{*sample},
149+
Metadata: writev2.Metadata{
150+
Type: metadata.Type,
151+
HelpRef: c.symbolTable.Symbolize(metadata.Help),
152+
UnitRef: c.symbolTable.Symbolize(metadata.Unit),
153+
},
137154
}
138155
c.unique[timeSeriesSignature(lbls)] = &ts
139156
}

pkg/translator/prometheusremotewrite/metrics_to_prw_v2_test.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,29 @@ func TestFromMetricsV2(t *testing.T) {
2727
payload := createExportRequest(5, 0, 1, 3, 0, pcommon.Timestamp(ts))
2828
want := []*writev2.TimeSeries{
2929
{
30-
LabelsRefs: []uint32{1, 2, 3, 4, 5, 6, 7, 8},
30+
LabelsRefs: []uint32{1, 11, 3, 4, 5, 6, 7, 8},
3131
Samples: []writev2.Sample{
3232
{Timestamp: convertTimeStamp(pcommon.Timestamp(ts)), Value: 1.23},
3333
},
34+
Metadata: writev2.Metadata{
35+
Type: writev2.Metadata_METRIC_TYPE_GAUGE,
36+
HelpRef: 12,
37+
UnitRef: 10,
38+
},
3439
},
3540
{
36-
LabelsRefs: []uint32{1, 9, 3, 4, 5, 6, 7, 8},
41+
LabelsRefs: []uint32{1, 2, 3, 4, 5, 6, 7, 8},
3742
Samples: []writev2.Sample{
3843
{Timestamp: convertTimeStamp(pcommon.Timestamp(ts)), Value: 1.23},
3944
},
45+
Metadata: writev2.Metadata{
46+
Type: writev2.Metadata_METRIC_TYPE_GAUGE,
47+
HelpRef: 9,
48+
UnitRef: 10,
49+
},
4050
},
4151
}
42-
wantedSymbols := []string{"", "series_name_2", "value-2", "series_name_3", "value-3", "__name__", "gauge_1", "series_name_1", "value-1", "sum_1"}
52+
wantedSymbols := []string{"", "series_name_2", "value-2", "series_name_3", "value-3", "__name__", "gauge_1", "series_name_1", "value-1", "sum_1", "test gauge description", "test sum description", "bytes"}
4353
tsMap, symbolsTable, err := FromMetricsV2(payload.Metrics(), settings)
4454
require.NoError(t, err)
4555
require.ElementsMatch(t, want, slices.Collect(maps.Values(tsMap)))

pkg/translator/prometheusremotewrite/number_data_points_v2.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
)
1616

1717
func (c *prometheusConverterV2) addGaugeNumberDataPoints(dataPoints pmetric.NumberDataPointSlice,
18-
resource pcommon.Resource, settings Settings, name string,
18+
resource pcommon.Resource, settings Settings, name string, metadata metadata,
1919
) {
2020
for x := 0; x < dataPoints.Len(); x++ {
2121
pt := dataPoints.At(x)
@@ -43,12 +43,12 @@ func (c *prometheusConverterV2) addGaugeNumberDataPoints(dataPoints pmetric.Numb
4343
if pt.Flags().NoRecordedValue() {
4444
sample.Value = math.Float64frombits(value.StaleNaN)
4545
}
46-
c.addSample(sample, labels)
46+
c.addSample(sample, labels, metadata)
4747
}
4848
}
4949

5050
func (c *prometheusConverterV2) addSumNumberDataPoints(dataPoints pmetric.NumberDataPointSlice,
51-
resource pcommon.Resource, _ pmetric.Metric, settings Settings, name string,
51+
resource pcommon.Resource, _ pmetric.Metric, settings Settings, name string, metadata metadata,
5252
) {
5353
for x := 0; x < dataPoints.Len(); x++ {
5454
pt := dataPoints.At(x)
@@ -76,7 +76,7 @@ func (c *prometheusConverterV2) addSumNumberDataPoints(dataPoints pmetric.Number
7676
sample.Value = math.Float64frombits(value.StaleNaN)
7777
}
7878
// TODO: properly add exemplars to the TimeSeries
79-
c.addSample(sample, lbls)
79+
c.addSample(sample, lbls, metadata)
8080
}
8181
}
8282

pkg/translator/prometheusremotewrite/number_data_points_v2_test.go

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import (
1616
"github.com/stretchr/testify/assert"
1717
"go.opentelemetry.io/collector/pdata/pcommon"
1818
"go.opentelemetry.io/collector/pdata/pmetric"
19+
20+
prometheustranslator "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus"
1921
)
2022

2123
func TestPrometheusConverterV2_addGaugeNumberDataPoints(t *testing.T) {
@@ -47,6 +49,11 @@ func TestPrometheusConverterV2_addGaugeNumberDataPoints(t *testing.T) {
4749
Samples: []writev2.Sample{
4850
{Timestamp: convertTimeStamp(pcommon.Timestamp(ts)), Value: 1},
4951
},
52+
Metadata: writev2.Metadata{
53+
Type: writev2.Metadata_METRIC_TYPE_GAUGE,
54+
HelpRef: 3,
55+
UnitRef: 4,
56+
},
5057
},
5158
}
5259
},
@@ -73,6 +80,11 @@ func TestPrometheusConverterV2_addGaugeNumberDataPoints(t *testing.T) {
7380
Samples: []writev2.Sample{
7481
{Timestamp: convertTimeStamp(pcommon.Timestamp(ts)), Value: 1.5},
7582
},
83+
Metadata: writev2.Metadata{
84+
Type: writev2.Metadata_METRIC_TYPE_GAUGE,
85+
HelpRef: 3,
86+
UnitRef: 4,
87+
},
7688
},
7789
}
7890
},
@@ -99,6 +111,11 @@ func TestPrometheusConverterV2_addGaugeNumberDataPoints(t *testing.T) {
99111
Samples: []writev2.Sample{
100112
{Timestamp: convertTimeStamp(pcommon.Timestamp(ts)), Value: math.Float64frombits(value.StaleNaN)},
101113
},
114+
Metadata: writev2.Metadata{
115+
Type: writev2.Metadata_METRIC_TYPE_GAUGE,
116+
HelpRef: 3,
117+
UnitRef: 4,
118+
},
102119
},
103120
}
104121
},
@@ -115,7 +132,12 @@ func TestPrometheusConverterV2_addGaugeNumberDataPoints(t *testing.T) {
115132
SendMetadata: false,
116133
}
117134
converter := newPrometheusConverterV2()
118-
converter.addGaugeNumberDataPoints(metric.Gauge().DataPoints(), pcommon.NewResource(), settings, metric.Name())
135+
m := metadata{
136+
Type: otelMetricTypeToPromMetricTypeV2(metric),
137+
Help: metric.Description(),
138+
Unit: prometheustranslator.BuildCompliantPrometheusUnit(metric.Unit()),
139+
}
140+
converter.addGaugeNumberDataPoints(metric.Gauge().DataPoints(), pcommon.NewResource(), settings, metric.Name(), m)
119141
w := tt.want()
120142

121143
diff := cmp.Diff(w, converter.unique, cmpopts.EquateNaNs())
@@ -151,6 +173,11 @@ func TestPrometheusConverterV2_addGaugeNumberDataPointsDuplicate(t *testing.T) {
151173
Samples: []writev2.Sample{
152174
{Timestamp: convertTimeStamp(pcommon.Timestamp(ts)), Value: 2},
153175
},
176+
Metadata: writev2.Metadata{
177+
Type: writev2.Metadata_METRIC_TYPE_GAUGE,
178+
HelpRef: 3,
179+
UnitRef: 4,
180+
},
154181
},
155182
}
156183
}
@@ -163,8 +190,19 @@ func TestPrometheusConverterV2_addGaugeNumberDataPointsDuplicate(t *testing.T) {
163190
}
164191

165192
converter := newPrometheusConverterV2()
166-
converter.addGaugeNumberDataPoints(metric1.Gauge().DataPoints(), pcommon.NewResource(), settings, metric1.Name())
167-
converter.addGaugeNumberDataPoints(metric2.Gauge().DataPoints(), pcommon.NewResource(), settings, metric2.Name())
193+
m1 := metadata{
194+
Type: otelMetricTypeToPromMetricTypeV2(metric1),
195+
Help: metric1.Description(),
196+
Unit: prometheustranslator.BuildCompliantPrometheusUnit(metric1.Unit()),
197+
}
198+
converter.addGaugeNumberDataPoints(metric1.Gauge().DataPoints(), pcommon.NewResource(), settings, metric1.Name(), m1)
199+
200+
m2 := metadata{
201+
Type: otelMetricTypeToPromMetricTypeV2(metric2),
202+
Help: metric2.Description(),
203+
Unit: prometheustranslator.BuildCompliantPrometheusUnit(metric2.Unit()),
204+
}
205+
converter.addGaugeNumberDataPoints(metric2.Gauge().DataPoints(), pcommon.NewResource(), settings, metric2.Name(), m2)
168206

169207
assert.Equal(t, want(), converter.unique)
170208
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package prometheusremotewrite // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheusremotewrite"
5+
6+
import (
7+
"github.com/prometheus/common/model"
8+
writev2 "github.com/prometheus/prometheus/prompb/io/prometheus/write/v2"
9+
"go.opentelemetry.io/collector/pdata/pmetric"
10+
11+
prometheustranslator "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus"
12+
)
13+
14+
func otelMetricTypeToPromMetricTypeV2(otelMetric pmetric.Metric) writev2.Metadata_MetricType {
15+
// metric metadata can be used to support Prometheus types that don't exist
16+
// in OpenTelemetry.
17+
typeFromMetadata, hasTypeFromMetadata := otelMetric.Metadata().Get(prometheustranslator.MetricMetadataTypeKey)
18+
switch otelMetric.Type() {
19+
case pmetric.MetricTypeGauge:
20+
if hasTypeFromMetadata && typeFromMetadata.Str() == string(model.MetricTypeUnknown) {
21+
return writev2.Metadata_METRIC_TYPE_UNSPECIFIED
22+
}
23+
return writev2.Metadata_METRIC_TYPE_GAUGE
24+
case pmetric.MetricTypeSum:
25+
if otelMetric.Sum().IsMonotonic() {
26+
return writev2.Metadata_METRIC_TYPE_COUNTER
27+
}
28+
if hasTypeFromMetadata && typeFromMetadata.Str() == string(model.MetricTypeInfo) {
29+
return writev2.Metadata_METRIC_TYPE_INFO
30+
}
31+
if hasTypeFromMetadata && typeFromMetadata.Str() == string(model.MetricTypeStateset) {
32+
return writev2.Metadata_METRIC_TYPE_STATESET
33+
}
34+
return writev2.Metadata_METRIC_TYPE_GAUGE
35+
case pmetric.MetricTypeHistogram:
36+
return writev2.Metadata_METRIC_TYPE_HISTOGRAM
37+
case pmetric.MetricTypeSummary:
38+
return writev2.Metadata_METRIC_TYPE_SUMMARY
39+
case pmetric.MetricTypeExponentialHistogram:
40+
return writev2.Metadata_METRIC_TYPE_HISTOGRAM
41+
}
42+
return writev2.Metadata_METRIC_TYPE_UNSPECIFIED
43+
}

0 commit comments

Comments
 (0)