Skip to content

Commit e55f121

Browse files
committed
split otel exports into chunks
1 parent 4cf5954 commit e55f121

6 files changed

Lines changed: 665 additions & 13 deletions

File tree

Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
package com.linkedin.venice.stats;
2+
3+
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
4+
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
5+
import io.opentelemetry.sdk.metrics.data.Data;
6+
import io.opentelemetry.sdk.metrics.data.DoublePointData;
7+
import io.opentelemetry.sdk.metrics.data.ExponentialHistogramData;
8+
import io.opentelemetry.sdk.metrics.data.ExponentialHistogramPointData;
9+
import io.opentelemetry.sdk.metrics.data.GaugeData;
10+
import io.opentelemetry.sdk.metrics.data.HistogramData;
11+
import io.opentelemetry.sdk.metrics.data.HistogramPointData;
12+
import io.opentelemetry.sdk.metrics.data.LongPointData;
13+
import io.opentelemetry.sdk.metrics.data.MetricData;
14+
import io.opentelemetry.sdk.metrics.data.MetricDataType;
15+
import io.opentelemetry.sdk.metrics.data.PointData;
16+
import io.opentelemetry.sdk.metrics.data.SumData;
17+
import io.opentelemetry.sdk.metrics.data.SummaryData;
18+
import io.opentelemetry.sdk.metrics.data.SummaryPointData;
19+
import io.opentelemetry.sdk.metrics.internal.data.ImmutableSumData;
20+
import io.opentelemetry.sdk.resources.Resource;
21+
import java.util.AbstractCollection;
22+
import java.util.Collection;
23+
import java.util.Iterator;
24+
import java.util.NoSuchElementException;
25+
26+
27+
/**
28+
* A decorator for {@link MetricData} that restricts the range of points returned
29+
* based on the specified start and end indices.
30+
*
31+
* <p>This allows selective access to a subset of data points within a given metric.
32+
* The decorator ensures that only points within the specified index range are accessible.
33+
*
34+
* <p>Usage Example:
35+
* <pre>
36+
* MetricData originalMetricData = ...;
37+
* MetricDataRangeDecorator decorator = new MetricDataRangeDecorator(originalMetricData, 2, 5);
38+
* Collection<PointData> filteredPoints = decorator.getData().getPoints();
39+
* </pre>
40+
*
41+
* @param <T> The type of {@link PointData} contained in the metric data.
42+
*/
43+
public class MetricDataRangeDecorator<T extends PointData> implements MetricData {
44+
private final MetricData originalMetricData;
45+
private final int startIndex;
46+
private final int endIndex;
47+
48+
public MetricDataRangeDecorator(MetricData originalMetricData, int startIndex, int endIndex) {
49+
if (startIndex < 0 || endIndex > originalMetricData.getData().getPoints().size() || startIndex > endIndex) {
50+
throw new IllegalArgumentException("Invalid range specified");
51+
}
52+
this.originalMetricData = originalMetricData;
53+
this.startIndex = startIndex;
54+
this.endIndex = endIndex;
55+
}
56+
57+
@Override
58+
public MetricDataType getType() {
59+
return originalMetricData.getType();
60+
}
61+
62+
@Override
63+
public String getName() {
64+
return originalMetricData.getName();
65+
}
66+
67+
@Override
68+
public String getDescription() {
69+
return originalMetricData.getDescription();
70+
}
71+
72+
@Override
73+
public String getUnit() {
74+
return originalMetricData.getUnit();
75+
}
76+
77+
@Override
78+
public Resource getResource() {
79+
return originalMetricData.getResource();
80+
}
81+
82+
@Override
83+
public InstrumentationScopeInfo getInstrumentationScopeInfo() {
84+
return originalMetricData.getInstrumentationScopeInfo();
85+
}
86+
87+
/**
88+
* Returns the metric data for the specified type.
89+
*
90+
* <p>This method decorates the original metric data with a range filter applied to the points.
91+
* It ensures that the returned data is of the correct type and can be cast to the expected type
92+
* in the calling code.
93+
*
94+
* @return the metric data with the range filter applied.
95+
* @throws ClassCastException if the original metric data is not of the expected type.
96+
*/
97+
@Override
98+
public Data<?> getData() {
99+
Data<?> originalData = originalMetricData.getData();
100+
101+
switch (originalMetricData.getType()) {
102+
case EXPONENTIAL_HISTOGRAM:
103+
return new ExponentialHistogramData() {
104+
@Override
105+
public AggregationTemporality getAggregationTemporality() {
106+
return ((ExponentialHistogramData) originalData).getAggregationTemporality();
107+
}
108+
109+
@Override
110+
public Collection<ExponentialHistogramPointData> getPoints() {
111+
return createPointCollection((ExponentialHistogramData) originalData);
112+
}
113+
};
114+
115+
case DOUBLE_GAUGE:
116+
return new GaugeData<DoublePointData>() {
117+
@Override
118+
public Collection<DoublePointData> getPoints() {
119+
return createPointCollection((GaugeData<DoublePointData>) originalData);
120+
}
121+
};
122+
123+
case LONG_GAUGE:
124+
return new GaugeData<LongPointData>() {
125+
@Override
126+
public Collection<LongPointData> getPoints() {
127+
return createPointCollection((GaugeData<LongPointData>) originalData);
128+
}
129+
};
130+
131+
case DOUBLE_SUM:
132+
return new SumData<DoublePointData>() {
133+
@Override
134+
public AggregationTemporality getAggregationTemporality() {
135+
return ((ImmutableSumData<DoublePointData>) originalData).getAggregationTemporality();
136+
}
137+
138+
@Override
139+
public Collection<DoublePointData> getPoints() {
140+
return createPointCollection((ImmutableSumData<DoublePointData>) originalData);
141+
}
142+
143+
@Override
144+
public boolean isMonotonic() {
145+
return ((ImmutableSumData<DoublePointData>) originalData).isMonotonic();
146+
}
147+
};
148+
149+
case LONG_SUM:
150+
return new SumData<LongPointData>() {
151+
@Override
152+
public AggregationTemporality getAggregationTemporality() {
153+
return ((ImmutableSumData<LongPointData>) originalData).getAggregationTemporality();
154+
}
155+
156+
@Override
157+
public Collection<LongPointData> getPoints() {
158+
return createPointCollection((ImmutableSumData<LongPointData>) originalData);
159+
}
160+
161+
@Override
162+
public boolean isMonotonic() {
163+
return ((ImmutableSumData<LongPointData>) originalData).isMonotonic();
164+
}
165+
};
166+
167+
case HISTOGRAM:
168+
return new HistogramData() {
169+
@Override
170+
public AggregationTemporality getAggregationTemporality() {
171+
return ((HistogramData) originalData).getAggregationTemporality();
172+
}
173+
174+
@Override
175+
public Collection<HistogramPointData> getPoints() {
176+
return createPointCollection((HistogramData) originalData);
177+
}
178+
};
179+
180+
case SUMMARY:
181+
return new SummaryData() {
182+
@Override
183+
public Collection<SummaryPointData> getPoints() {
184+
return createPointCollection((SummaryData) originalData);
185+
}
186+
};
187+
188+
default:
189+
throw new IllegalStateException("Unsupported MetricData type: " + originalMetricData.getType());
190+
}
191+
}
192+
193+
/**
194+
* Override the open source method only to help type cast to SumData.
195+
*/
196+
@Override
197+
public SumData<DoublePointData> getDoubleSumData() {
198+
if (getType() == MetricDataType.DOUBLE_SUM) {
199+
return (SumData<DoublePointData>) getData();
200+
}
201+
return ImmutableSumData.empty();
202+
}
203+
204+
/**
205+
* Creates a collection that wraps the original points and applies the range filter.
206+
*/
207+
private <T extends PointData> Collection<T> createPointCollection(Data<T> originalData) {
208+
return new AbstractCollection<T>() {
209+
@Override
210+
public Iterator<T> iterator() {
211+
return new RangeIterator<>(originalData.getPoints().iterator(), startIndex, endIndex);
212+
}
213+
214+
@Override
215+
public int size() {
216+
return Math.max(0, endIndex - startIndex);
217+
}
218+
};
219+
}
220+
221+
/**
222+
* Compares this {@link MetricDataRangeDecorator} with the specified object for equality.
223+
*
224+
* <p>This method performs a one-way equality check:
225+
* <ul>
226+
* <li>If the object is the same instance, it returns {@code true}.</li>
227+
* <li>If the object is a {@link MetricDataRangeDecorator}, it compares the underlying
228+
* {@link MetricData} and the start and end indices of both decorators.</li>
229+
* <li>If the object is a plain {@link MetricData}, it is considered equal only if the
230+
* decorator represents the full range (start index = 0, end index = size of points)
231+
* and the underlying {@link MetricData} is equal.</li>
232+
* </ul>
233+
*
234+
* <p><b>Note:</b> This equality comparison works only one way:
235+
* - {@code decorator.equals(original)} will return {@code true} if the decorator covers the full range.
236+
* - {@code original.equals(decorator)} will always return {@code false}.
237+
*
238+
* @param obj the object to compare this decorator with
239+
* @return {@code true} if the object is equal to this decorator; {@code false} otherwise
240+
*/
241+
@Override
242+
public boolean equals(Object obj) {
243+
if (this == obj) {
244+
return true;
245+
}
246+
if (obj instanceof MetricDataRangeDecorator) {
247+
MetricDataRangeDecorator<?> other = (MetricDataRangeDecorator<?>) obj;
248+
return this.startIndex == other.startIndex && this.endIndex == other.endIndex
249+
&& this.originalMetricData.equals(other.originalMetricData);
250+
}
251+
return this.startIndex == 0 && this.endIndex == originalMetricData.getData().getPoints().size()
252+
&& originalMetricData.equals(obj);
253+
}
254+
255+
@Override
256+
public int hashCode() {
257+
if (startIndex == 0 && endIndex == originalMetricData.getData().getPoints().size()) {
258+
return originalMetricData.hashCode();
259+
}
260+
return 31 * originalMetricData.hashCode() + startIndex + endIndex;
261+
}
262+
263+
@Override
264+
public String toString() {
265+
return "MetricDataRangeDecorator{" + "originalMetricData=" + originalMetricData + ", startIndex=" + startIndex
266+
+ ", endIndex=" + endIndex + '}';
267+
}
268+
269+
/**
270+
* An iterator that applies a range filter to the original iterator.
271+
*/
272+
private static class RangeIterator<T> implements Iterator<T> {
273+
private final Iterator<T> iterator;
274+
private final int endIndex;
275+
private int currentIndex = 0;
276+
277+
RangeIterator(Iterator<T> iterator, int startIndex, int endIndex) {
278+
this.iterator = iterator;
279+
this.endIndex = endIndex;
280+
281+
// Skip elements until reaching startIndex
282+
while (currentIndex < startIndex && iterator.hasNext()) {
283+
iterator.next();
284+
currentIndex++;
285+
}
286+
}
287+
288+
@Override
289+
public boolean hasNext() {
290+
return currentIndex < endIndex && iterator.hasNext();
291+
}
292+
293+
@Override
294+
public T next() {
295+
if (!hasNext()) {
296+
throw new NoSuchElementException();
297+
}
298+
currentIndex++;
299+
return iterator.next();
300+
}
301+
}
302+
}

0 commit comments

Comments
 (0)