Skip to content

Commit 0c757ee

Browse files
Jm prom translation rw2 add support for summaries (#40750)
<!--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 adding summaries 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] Added unit test * [ ] e2e ran with prometheus Review please @ArthurSens @dashpole @krajorama @ywwg --------- Co-authored-by: David Ashpole <[email protected]>
1 parent eb7bd76 commit 0c757ee

File tree

4 files changed

+202
-1
lines changed

4 files changed

+202
-1
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: pkg/translator/prometheusremotewrite
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: "`FromMetricsV2` now supports translating summaries."
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [33661]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext: The translation layer for Prometheus remote write 2 now supports summaries but is not fully implemented and ready for use.
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

pkg/translator/prometheusremotewrite/helper_v2.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@
44
package prometheusremotewrite // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheusremotewrite"
55

66
import (
7+
"math"
8+
"strconv"
9+
710
"github.com/prometheus/common/model"
11+
"github.com/prometheus/prometheus/model/value"
12+
"github.com/prometheus/prometheus/prompb"
813
writev2 "github.com/prometheus/prometheus/prompb/io/prometheus/write/v2"
914
"go.opentelemetry.io/collector/pdata/pcommon"
15+
"go.opentelemetry.io/collector/pdata/pmetric"
1016
conventions "go.opentelemetry.io/otel/semconv/v1.25.0"
1117

1218
prometheustranslator "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus"
@@ -66,3 +72,43 @@ func (c *prometheusConverterV2) addResourceTargetInfoV2(resource pcommon.Resourc
6672
Help: "Target metadata",
6773
})
6874
}
75+
76+
// addSampleWithLabels is a helper function to create and add a sample with labels
77+
func (c *prometheusConverterV2) addSampleWithLabels(sampleValue float64, timestamp int64, noRecordedValue bool,
78+
baseName string, baseLabels []prompb.Label, labelName, labelValue string, metadata metadata,
79+
) {
80+
sample := &writev2.Sample{
81+
Value: sampleValue,
82+
Timestamp: timestamp,
83+
}
84+
if noRecordedValue {
85+
sample.Value = math.Float64frombits(value.StaleNaN)
86+
}
87+
if labelName != "" && labelValue != "" {
88+
c.addSample(sample, createLabels(baseName, baseLabels, labelName, labelValue), metadata)
89+
} else {
90+
c.addSample(sample, createLabels(baseName, baseLabels), metadata)
91+
}
92+
}
93+
94+
func (c *prometheusConverterV2) addSummaryDataPoints(dataPoints pmetric.SummaryDataPointSlice, resource pcommon.Resource,
95+
settings Settings, baseName string, metadata metadata,
96+
) {
97+
for x := 0; x < dataPoints.Len(); x++ {
98+
pt := dataPoints.At(x)
99+
timestamp := convertTimeStamp(pt.Timestamp())
100+
baseLabels := createAttributes(resource, pt.Attributes(), settings.ExternalLabels, nil, false)
101+
noRecordedValue := pt.Flags().NoRecordedValue()
102+
103+
// Add sum and count samples
104+
c.addSampleWithLabels(pt.Sum(), timestamp, noRecordedValue, baseName+sumStr, baseLabels, "", "", metadata)
105+
c.addSampleWithLabels(float64(pt.Count()), timestamp, noRecordedValue, baseName+countStr, baseLabels, "", "", metadata)
106+
107+
// Process quantiles
108+
for i := 0; i < pt.QuantileValues().Len(); i++ {
109+
qt := pt.QuantileValues().At(i)
110+
percentileStr := strconv.FormatFloat(qt.Quantile(), 'f', -1, 64)
111+
c.addSampleWithLabels(qt.Value(), timestamp, noRecordedValue, baseName, baseLabels, quantileStr, percentileStr, metadata)
112+
}
113+
}
114+
}

pkg/translator/prometheusremotewrite/helper_v2_test.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,19 @@ package prometheusremotewrite
55

66
import (
77
"testing"
8+
"time"
89

910
"github.com/prometheus/common/model"
1011
"github.com/prometheus/prometheus/prompb"
1112
writev2 "github.com/prometheus/prometheus/prompb/io/prometheus/write/v2"
1213
"github.com/stretchr/testify/assert"
1314
"github.com/stretchr/testify/require"
1415
"go.opentelemetry.io/collector/pdata/pcommon"
16+
"go.opentelemetry.io/collector/pdata/pmetric"
1517
conventions "go.opentelemetry.io/otel/semconv/v1.25.0"
1618

1719
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/testdata"
20+
prometheustranslator "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus"
1821
)
1922

2023
func TestAddResourceTargetInfoV2(t *testing.T) {
@@ -153,3 +156,124 @@ func TestAddResourceTargetInfoV2(t *testing.T) {
153156
})
154157
}
155158
}
159+
160+
func TestPrometheusConverterV2_AddSummaryDataPoints(t *testing.T) {
161+
ts := pcommon.Timestamp(time.Now().UnixNano())
162+
tests := []struct {
163+
name string
164+
metric func() pmetric.Metric
165+
want func() map[uint64]*writev2.TimeSeries
166+
}{
167+
{
168+
name: "summary with start time",
169+
metric: func() pmetric.Metric {
170+
metric := pmetric.NewMetric()
171+
metric.SetName("test_summary")
172+
metric.SetEmptySummary()
173+
174+
dp := metric.Summary().DataPoints().AppendEmpty()
175+
dp.SetTimestamp(ts)
176+
dp.SetStartTimestamp(ts)
177+
178+
return metric
179+
},
180+
want: func() map[uint64]*writev2.TimeSeries {
181+
labels := []prompb.Label{
182+
{Name: model.MetricNameLabel, Value: "test_summary" + countStr},
183+
}
184+
sumLabels := []prompb.Label{
185+
{Name: model.MetricNameLabel, Value: "test_summary" + sumStr},
186+
}
187+
return map[uint64]*writev2.TimeSeries{
188+
timeSeriesSignature(labels): {
189+
LabelsRefs: []uint32{1, 3},
190+
Samples: []writev2.Sample{
191+
{Value: 0, Timestamp: convertTimeStamp(ts)},
192+
},
193+
Metadata: writev2.Metadata{
194+
Type: writev2.Metadata_METRIC_TYPE_SUMMARY,
195+
HelpRef: 0,
196+
},
197+
},
198+
timeSeriesSignature(sumLabels): {
199+
LabelsRefs: []uint32{1, 2},
200+
Samples: []writev2.Sample{
201+
{Value: 0, Timestamp: convertTimeStamp(ts)},
202+
},
203+
Metadata: writev2.Metadata{
204+
Type: writev2.Metadata_METRIC_TYPE_SUMMARY,
205+
HelpRef: 0,
206+
},
207+
},
208+
}
209+
},
210+
},
211+
{
212+
name: "summary without start time",
213+
metric: func() pmetric.Metric {
214+
metric := pmetric.NewMetric()
215+
metric.SetName("test_summary")
216+
metric.SetEmptySummary()
217+
218+
dp := metric.Summary().DataPoints().AppendEmpty()
219+
dp.SetTimestamp(ts)
220+
221+
return metric
222+
},
223+
want: func() map[uint64]*writev2.TimeSeries {
224+
labels := []prompb.Label{
225+
{Name: model.MetricNameLabel, Value: "test_summary" + countStr},
226+
}
227+
sumLabels := []prompb.Label{
228+
{Name: model.MetricNameLabel, Value: "test_summary" + sumStr},
229+
}
230+
return map[uint64]*writev2.TimeSeries{
231+
timeSeriesSignature(labels): {
232+
LabelsRefs: []uint32{1, 3},
233+
Samples: []writev2.Sample{
234+
{Value: 0, Timestamp: convertTimeStamp(ts)},
235+
},
236+
Metadata: writev2.Metadata{
237+
Type: writev2.Metadata_METRIC_TYPE_SUMMARY,
238+
HelpRef: 0,
239+
},
240+
},
241+
timeSeriesSignature(sumLabels): {
242+
LabelsRefs: []uint32{1, 2},
243+
Samples: []writev2.Sample{
244+
{Value: 0, Timestamp: convertTimeStamp(ts)},
245+
},
246+
Metadata: writev2.Metadata{
247+
Type: writev2.Metadata_METRIC_TYPE_SUMMARY,
248+
HelpRef: 0,
249+
},
250+
},
251+
}
252+
},
253+
},
254+
}
255+
for _, tt := range tests {
256+
t.Run(tt.name, func(t *testing.T) {
257+
metric := tt.metric()
258+
converter := newPrometheusConverterV2()
259+
260+
m := metadata{
261+
Type: otelMetricTypeToPromMetricTypeV2(metric),
262+
Help: metric.Description(),
263+
Unit: prometheustranslator.BuildCompliantPrometheusUnit(metric.Unit()),
264+
}
265+
266+
converter.addSummaryDataPoints(
267+
metric.Summary().DataPoints(),
268+
pcommon.NewResource(),
269+
Settings{},
270+
metric.Name(),
271+
m,
272+
)
273+
274+
assert.Equal(t, tt.want(), converter.unique)
275+
// TODO check when conflicts handling is implemented
276+
// assert.Empty(t, converter.conflicts)
277+
})
278+
}
279+
}

pkg/translator/prometheusremotewrite/metrics_to_prw_v2.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,11 @@ func (c *prometheusConverterV2) fromMetrics(md pmetric.Metrics, settings Setting
105105
case pmetric.MetricTypeExponentialHistogram:
106106
// TODO implement
107107
case pmetric.MetricTypeSummary:
108-
// TODO implement
108+
dataPoints := metric.Summary().DataPoints()
109+
if dataPoints.Len() == 0 {
110+
break
111+
}
112+
c.addSummaryDataPoints(dataPoints, resource, settings, promName, m)
109113
default:
110114
errs = multierr.Append(errs, errors.New("unsupported metric type"))
111115
}

0 commit comments

Comments
 (0)