7
7
8
8
package org .elasticsearch .xpack .oteldata .otlp ;
9
9
10
+ import io .opentelemetry .api .common .AttributeKey ;
10
11
import io .opentelemetry .api .common .Attributes ;
11
12
import io .opentelemetry .api .metrics .Meter ;
12
13
import io .opentelemetry .exporter .otlp .http .metrics .OtlpHttpMetricExporter ;
15
16
import io .opentelemetry .sdk .common .InstrumentationScopeInfo ;
16
17
import io .opentelemetry .sdk .metrics .SdkMeterProvider ;
17
18
import io .opentelemetry .sdk .metrics .data .AggregationTemporality ;
19
+ import io .opentelemetry .sdk .metrics .data .ExponentialHistogramBuckets ;
20
+ import io .opentelemetry .sdk .metrics .data .HistogramData ;
21
+ import io .opentelemetry .sdk .metrics .data .HistogramPointData ;
18
22
import io .opentelemetry .sdk .metrics .data .MetricData ;
19
23
import io .opentelemetry .sdk .metrics .export .PeriodicMetricReader ;
20
24
import io .opentelemetry .sdk .metrics .internal .data .ImmutableDoublePointData ;
25
+ import io .opentelemetry .sdk .metrics .internal .data .ImmutableExponentialHistogramData ;
26
+ import io .opentelemetry .sdk .metrics .internal .data .ImmutableExponentialHistogramPointData ;
21
27
import io .opentelemetry .sdk .metrics .internal .data .ImmutableGaugeData ;
22
28
import io .opentelemetry .sdk .metrics .internal .data .ImmutableLongPointData ;
23
29
import io .opentelemetry .sdk .metrics .internal .data .ImmutableMetricData ;
48
54
import static io .opentelemetry .api .common .AttributeKey .stringKey ;
49
55
import static io .opentelemetry .sdk .metrics .data .AggregationTemporality .CUMULATIVE ;
50
56
import static io .opentelemetry .sdk .metrics .data .AggregationTemporality .DELTA ;
57
+ import static org .elasticsearch .test .rest .ObjectPath .evaluate ;
51
58
import static org .elasticsearch .xpack .oteldata .otlp .OTLPMetricsIndexingRestIT .Monotonicity .MONOTONIC ;
52
59
import static org .elasticsearch .xpack .oteldata .otlp .OTLPMetricsIndexingRestIT .Monotonicity .NON_MONOTONIC ;
53
60
import static org .hamcrest .Matchers .aMapWithSize ;
@@ -133,12 +140,12 @@ public void testIngestMetricViaMeterProvider() throws Exception {
133
140
ObjectPath search = search ("metrics-generic.otel-default" );
134
141
assertThat (search .toString (), search .evaluate ("hits.total.value" ), equalTo (1 ));
135
142
var source = search .evaluate ("hits.hits.0._source" );
136
- assertThat (ObjectPath . evaluate (source , "@timestamp" ), isA (String .class ));
137
- assertThat (ObjectPath . evaluate (source , "start_timestamp" ), isA (String .class ));
138
- assertThat (ObjectPath . evaluate (source , "_metric_names_hash" ), isA (String .class ));
143
+ assertThat (evaluate (source , "@timestamp" ), isA (String .class ));
144
+ assertThat (evaluate (source , "start_timestamp" ), isA (String .class ));
145
+ assertThat (evaluate (source , "_metric_names_hash" ), isA (String .class ));
139
146
assertThat (ObjectPath .<Number >evaluate (source , "metrics.jvm\\ .memory\\ .total" ).longValue (), equalTo (totalMemory ));
140
- assertThat (ObjectPath . evaluate (source , "unit" ), equalTo ("By" ));
141
- assertThat (ObjectPath . evaluate (source , "scope.name" ), equalTo ("io.opentelemetry.example.metrics" ));
147
+ assertThat (evaluate (source , "unit" ), equalTo ("By" ));
148
+ assertThat (evaluate (source , "scope.name" ), equalTo ("io.opentelemetry.example.metrics" ));
142
149
}
143
150
144
151
public void testIngestMetricDataViaMetricExporter () throws Exception {
@@ -150,13 +157,13 @@ public void testIngestMetricDataViaMetricExporter() throws Exception {
150
157
ObjectPath search = search ("metrics-generic.otel-default" );
151
158
assertThat (search .toString (), search .evaluate ("hits.total.value" ), equalTo (1 ));
152
159
var source = search .evaluate ("hits.hits.0._source" );
153
- assertThat (ObjectPath . evaluate (source , "@timestamp" ), equalTo (timestampAsString (now )));
154
- assertThat (ObjectPath . evaluate (source , "start_timestamp" ), equalTo (timestampAsString (now )));
155
- assertThat (ObjectPath . evaluate (source , "_metric_names_hash" ), isA (String .class ));
160
+ assertThat (evaluate (source , "@timestamp" ), equalTo (timestampAsString (now )));
161
+ assertThat (evaluate (source , "start_timestamp" ), equalTo (timestampAsString (now )));
162
+ assertThat (evaluate (source , "_metric_names_hash" ), isA (String .class ));
156
163
assertThat (ObjectPath .<Number >evaluate (source , "metrics.jvm\\ .memory\\ .total" ).longValue (), equalTo (totalMemory ));
157
- assertThat (ObjectPath . evaluate (source , "unit" ), equalTo ("By" ));
158
- assertThat (ObjectPath . evaluate (source , "resource.attributes.service\\ .name" ), equalTo ("elasticsearch" ));
159
- assertThat (ObjectPath . evaluate (source , "scope.name" ), equalTo ("io.opentelemetry.example.metrics" ));
164
+ assertThat (evaluate (source , "unit" ), equalTo ("By" ));
165
+ assertThat (evaluate (source , "resource.attributes.service\\ .name" ), equalTo ("elasticsearch" ));
166
+ assertThat (evaluate (source , "scope.name" ), equalTo ("io.opentelemetry.example.metrics" ));
160
167
}
161
168
162
169
public void testGroupingSameGroup () throws Exception {
@@ -197,11 +204,11 @@ public void testGauge() throws Exception {
197
204
createLongGauge (TEST_RESOURCE , Attributes .empty (), "long_gauge" , 42 , "By" , now )
198
205
)
199
206
);
200
- Map <String , Object > metrics = ObjectPath . evaluate (getMapping ("metrics-generic.otel-default" ), "properties.metrics.properties" );
201
- assertThat (ObjectPath . evaluate (metrics , "double_gauge.type" ), equalTo ("double" ));
202
- assertThat (ObjectPath . evaluate (metrics , "double_gauge.time_series_metric" ), equalTo ("gauge" ));
203
- assertThat (ObjectPath . evaluate (metrics , "long_gauge.type" ), equalTo ("long" ));
204
- assertThat (ObjectPath . evaluate (metrics , "long_gauge.time_series_metric" ), equalTo ("gauge" ));
207
+ Map <String , Object > metrics = evaluate (getMapping ("metrics-generic.otel-default" ), "properties.metrics.properties" );
208
+ assertThat (evaluate (metrics , "double_gauge.type" ), equalTo ("double" ));
209
+ assertThat (evaluate (metrics , "double_gauge.time_series_metric" ), equalTo ("gauge" ));
210
+ assertThat (evaluate (metrics , "long_gauge.type" ), equalTo ("long" ));
211
+ assertThat (evaluate (metrics , "long_gauge.time_series_metric" ), equalTo ("gauge" ));
205
212
}
206
213
207
214
public void testCounterTemporality () throws Exception {
@@ -213,11 +220,11 @@ public void testCounterTemporality() throws Exception {
213
220
)
214
221
);
215
222
216
- Map <String , Object > metrics = ObjectPath . evaluate (getMapping ("metrics-generic.otel-default" ), "properties.metrics.properties" );
217
- assertThat (ObjectPath . evaluate (metrics , "cumulative_counter.type" ), equalTo ("long" ));
218
- assertThat (ObjectPath . evaluate (metrics , "cumulative_counter.time_series_metric" ), equalTo ("counter" ));
219
- assertThat (ObjectPath . evaluate (metrics , "delta_counter.type" ), equalTo ("long" ));
220
- assertThat (ObjectPath . evaluate (metrics , "delta_counter.time_series_metric" ), equalTo ("gauge" ));
223
+ Map <String , Object > metrics = evaluate (getMapping ("metrics-generic.otel-default" ), "properties.metrics.properties" );
224
+ assertThat (evaluate (metrics , "cumulative_counter.type" ), equalTo ("long" ));
225
+ assertThat (evaluate (metrics , "cumulative_counter.time_series_metric" ), equalTo ("counter" ));
226
+ assertThat (evaluate (metrics , "delta_counter.type" ), equalTo ("long" ));
227
+ assertThat (evaluate (metrics , "delta_counter.time_series_metric" ), equalTo ("gauge" ));
221
228
}
222
229
223
230
public void testCounterMonotonicity () throws Exception {
@@ -230,11 +237,96 @@ public void testCounterMonotonicity() throws Exception {
230
237
)
231
238
);
232
239
233
- Map <String , Object > metrics = ObjectPath .evaluate (getMapping ("metrics-generic.otel-default" ), "properties.metrics.properties" );
234
- assertThat (ObjectPath .evaluate (metrics , "up_down_counter.type" ), equalTo ("long" ));
235
- assertThat (ObjectPath .evaluate (metrics , "up_down_counter.time_series_metric" ), equalTo ("gauge" ));
236
- assertThat (ObjectPath .evaluate (metrics , "up_down_counter_delta.type" ), equalTo ("long" ));
237
- assertThat (ObjectPath .evaluate (metrics , "up_down_counter_delta.time_series_metric" ), equalTo ("gauge" ));
240
+ Map <String , Object > metrics = evaluate (getMapping ("metrics-generic.otel-default" ), "properties.metrics.properties" );
241
+ assertThat (evaluate (metrics , "up_down_counter.type" ), equalTo ("long" ));
242
+ assertThat (evaluate (metrics , "up_down_counter.time_series_metric" ), equalTo ("gauge" ));
243
+ assertThat (evaluate (metrics , "up_down_counter_delta.type" ), equalTo ("long" ));
244
+ assertThat (evaluate (metrics , "up_down_counter_delta.time_series_metric" ), equalTo ("gauge" ));
245
+ }
246
+
247
+ public void testExponentialHistograms () throws Exception {
248
+ long now = Clock .getDefault ().now ();
249
+ export (List .of (createExponentialHistogram (now , "exponential_histogram" , DELTA , Attributes .empty ())));
250
+
251
+ Map <String , Object > mappings = evaluate (getMapping ("metrics-generic.otel-default" ), "properties.metrics.properties" );
252
+ assertThat (evaluate (mappings , "exponential_histogram.type" ), equalTo ("histogram" ));
253
+
254
+ // Get document and check values/counts array
255
+ ObjectPath search = search ("metrics-generic.otel-default" );
256
+ assertThat (search .toString (), search .evaluate ("hits.total.value" ), equalTo (1 ));
257
+ var source = search .evaluate ("hits.hits.0._source" );
258
+ assertThat (evaluate (source , "metrics.exponential_histogram.counts" ), equalTo (List .of (2 , 1 , 10 , 1 , 2 )));
259
+ assertThat (evaluate (source , "metrics.exponential_histogram.values" ), equalTo (List .of (-3.0 , -1.5 , 0.0 , 1.5 , 3.0 )));
260
+ }
261
+
262
+ public void testExponentialHistogramsAsAggregateMetricDouble () throws Exception {
263
+ long now = Clock .getDefault ().now ();
264
+ export (
265
+ List .of (
266
+ createExponentialHistogram (
267
+ now ,
268
+ "exponential_histogram_summary" ,
269
+ DELTA ,
270
+ Attributes .of (
271
+ AttributeKey .stringArrayKey ("elasticsearch.mapping.hints" ),
272
+ List .of ("aggregate_metric_double" , "_doc_count" )
273
+ )
274
+ )
275
+ )
276
+ );
277
+
278
+ Map <String , Object > mappings = evaluate (getMapping ("metrics-generic.otel-default" ), "properties.metrics.properties" );
279
+ assertThat (evaluate (mappings , "exponential_histogram_summary.type" ), equalTo ("aggregate_metric_double" ));
280
+
281
+ ObjectPath search = search ("metrics-generic.otel-default" );
282
+ assertThat (search .toString (), search .evaluate ("hits.total.value" ), equalTo (1 ));
283
+ var source = search .evaluate ("hits.hits.0._source" );
284
+ assertThat (evaluate (source , "_doc_count" ), equalTo (16 ));
285
+ assertThat (evaluate (source , "metrics.exponential_histogram_summary.value_count" ), equalTo (16 ));
286
+ assertThat (evaluate (source , "metrics.exponential_histogram_summary.sum" ), equalTo (10.0 ));
287
+ }
288
+
289
+ public void testHistogram () throws Exception {
290
+ long now = Clock .getDefault ().now ();
291
+ export (List .of (createHistogram (now , "histogram" , DELTA , Attributes .empty ())));
292
+
293
+ Map <String , Object > metrics = evaluate (getMapping ("metrics-generic.otel-default" ), "properties.metrics.properties" );
294
+ assertThat (evaluate (metrics , "histogram.type" ), equalTo ("histogram" ));
295
+
296
+ // Get document and check values/counts array
297
+ ObjectPath search = search ("metrics-generic.otel-default" );
298
+ assertThat (search .toString (), search .evaluate ("hits.total.value" ), equalTo (1 ));
299
+ var source = search .evaluate ("hits.hits.0._source" );
300
+ assertThat (evaluate (source , "metrics.histogram.counts" ), equalTo (List .of (1 , 2 , 3 , 4 , 5 , 6 )));
301
+ List <Double > values = evaluate (source , "metrics.histogram.values" );
302
+ assertThat (values , equalTo (List .of (1.0 , 3.0 , 5.0 , 7.0 , 9.0 , 10.0 )));
303
+ }
304
+
305
+ public void testHistogramAsAggregateMetricDouble () throws Exception {
306
+ long now = Clock .getDefault ().now ();
307
+ export (
308
+ List .of (
309
+ createHistogram (
310
+ now ,
311
+ "histogram_summary" ,
312
+ DELTA ,
313
+ Attributes .of (
314
+ AttributeKey .stringArrayKey ("elasticsearch.mapping.hints" ),
315
+ List .of ("aggregate_metric_double" , "_doc_count" )
316
+ )
317
+ )
318
+ )
319
+ );
320
+
321
+ Map <String , Object > metrics = evaluate (getMapping ("metrics-generic.otel-default" ), "properties.metrics.properties" );
322
+ assertThat (evaluate (metrics , "histogram_summary.type" ), equalTo ("aggregate_metric_double" ));
323
+
324
+ ObjectPath search = search ("metrics-generic.otel-default" );
325
+ assertThat (search .toString (), search .evaluate ("hits.total.value" ), equalTo (1 ));
326
+ var source = search .evaluate ("hits.hits.0._source" );
327
+ assertThat (evaluate (source , "_doc_count" ), equalTo (21 ));
328
+ assertThat (evaluate (source , "metrics.histogram_summary.value_count" ), equalTo (21 ));
329
+ assertThat (evaluate (source , "metrics.histogram_summary.sum" ), equalTo (10.0 ));
238
330
}
239
331
240
332
public void testTsidForBulkIsSame () throws Exception {
@@ -316,7 +408,7 @@ private static Map<String, Object> getMapping(String target) throws IOException
316
408
Map <String , Object > mappings = ObjectPath .createFromResponse (client ().performRequest (new Request ("GET" , target + "/_mapping" )))
317
409
.evaluate ("" );
318
410
assertThat (mappings , aMapWithSize (1 ));
319
- Map <String , Object > mapping = ObjectPath . evaluate (mappings .values ().iterator ().next (), "mappings" );
411
+ Map <String , Object > mapping = evaluate (mappings .values ().iterator ().next (), "mappings" );
320
412
assertThat (mapping , not (anEmptyMap ()));
321
413
return mapping ;
322
414
}
@@ -420,4 +512,66 @@ public boolean isMonotonic() {
420
512
return monotonic ;
421
513
}
422
514
}
515
+
516
+ private static MetricData createHistogram (long timeEpochNanos , String name , AggregationTemporality temporality , Attributes attributes ) {
517
+ return ImmutableMetricData .createDoubleHistogram (
518
+ TEST_RESOURCE ,
519
+ TEST_SCOPE ,
520
+ name ,
521
+ "Histogram Test" ,
522
+ "ms" ,
523
+ HistogramData .create (
524
+ temporality ,
525
+ List .of (
526
+ HistogramPointData .create (
527
+ timeEpochNanos ,
528
+ timeEpochNanos ,
529
+ attributes ,
530
+ 10 ,
531
+ false ,
532
+ 0 ,
533
+ false ,
534
+ 0 ,
535
+ List .of (2.0 , 4.0 , 6.0 , 8.0 , 10.0 ),
536
+ List .of (1L , 2L , 3L , 4L , 5L , 6L )
537
+ )
538
+ )
539
+ )
540
+ );
541
+ }
542
+
543
+ private static MetricData createExponentialHistogram (
544
+ long timeEpochNanos ,
545
+ String name ,
546
+ AggregationTemporality temporality ,
547
+ Attributes attributes
548
+ ) {
549
+ return ImmutableMetricData .createExponentialHistogram (
550
+ TEST_RESOURCE ,
551
+ TEST_SCOPE ,
552
+ name ,
553
+ "Exponential Histogram Test" ,
554
+ "ms" ,
555
+ ImmutableExponentialHistogramData .create (
556
+ temporality ,
557
+ List .of (
558
+ ImmutableExponentialHistogramPointData .create (
559
+ 0 ,
560
+ 10 ,
561
+ 10 ,
562
+ false ,
563
+ 0 ,
564
+ false ,
565
+ 0 ,
566
+ ExponentialHistogramBuckets .create (0 , 0 , List .of (1L , 2L )),
567
+ ExponentialHistogramBuckets .create (0 , 0 , List .of (1L , 2L )),
568
+ timeEpochNanos ,
569
+ timeEpochNanos ,
570
+ attributes ,
571
+ List .of ()
572
+ )
573
+ )
574
+ )
575
+ );
576
+ }
423
577
}
0 commit comments