@@ -27,6 +27,7 @@ import kamon.testkit.Reconfigure
27
27
import org .scalatest .matchers .should .Matchers
28
28
import org .scalatest .wordspec .AnyWordSpec
29
29
30
+ import java .lang .{Double => JDouble , Long => JLong }
30
31
import java .time .Instant
31
32
import java .util .{Collection => JCollection }
32
33
import scala .collection .JavaConverters ._
@@ -103,8 +104,80 @@ class OpenTelemetryMetricReporterSpec extends AnyWordSpec
103
104
points.head.getAttributes.get(AttributeKey .stringKey(" tag1" )) should equal(" value1" )
104
105
points.head.getValue shouldEqual 42L
105
106
}
107
+ " send histogram metrics" in {
108
+ val (reporter, mockService) = openTelemetryMetricsReporter()
109
+ val now = Instant .now()
110
+ reporter.reportPeriodSnapshot(
111
+ PeriodSnapshot .apply(
112
+ now.minusMillis(1000 ),
113
+ now,
114
+ Nil ,
115
+ Nil ,
116
+ MetricSnapshot .ofDistributions(
117
+ " test.histogram" ,
118
+ " test" ,
119
+ Metric .Settings .ForDistributionInstrument (MeasurementUnit .none, java.time.Duration .ZERO , DynamicRange .Default ),
120
+ Instrument .Snapshot (
121
+ TagSet .from(Map (" tag1" -> " value1" )),
122
+ buildHistogramDist(Seq (1L -> 2L , 2L -> 2L , 3L -> 3L ))
123
+ ) :: Nil ) :: Nil ,
124
+ Nil ,
125
+ Nil
126
+ )
127
+ )
128
+ // basic sanity
129
+ mockService.exportMetricsServiceRequest should not be empty
130
+ mockService.exportMetricsServiceRequest.get should have size 1
131
+ val exportedMetrics : Seq [MetricData ] = mockService.exportMetricsServiceRequest.get.asScala.toSeq
132
+ exportedMetrics should have size 1
133
+ val metricData = exportedMetrics.head
134
+
135
+
136
+ // check value
137
+ metricData.getName should equal(" test.histogram" )
138
+ metricData.getDescription should equal(" test" )
139
+ val sumData = metricData.getHistogramData
140
+ val points = sumData.getPoints.asScala.toSeq
141
+ points should have size 1
142
+ points.head.getAttributes should have size 1
143
+ points.head.getAttributes.get(AttributeKey .stringKey(" tag1" )) should equal(" value1" )
144
+ points.head.getMin shouldEqual 1L
145
+ points.head.getMax shouldEqual 3L
146
+ points.head.getSum shouldEqual 15L
147
+ points.head.getCount shouldEqual 7L
148
+ points.head.getBoundaries.asScala shouldEqual Seq [JDouble ](1d , 2d )
149
+ points.head.getCounts.asScala shouldEqual Seq [JDouble ](2d , 2d , 3d )
150
+ }
106
151
}
107
152
153
+ private def buildHistogramDist (_buckets : Seq [(Long , Long )]): Distribution = {
154
+
155
+ val distribution : Distribution = new Distribution () {
156
+ override def dynamicRange : DynamicRange = DynamicRange .Default
157
+
158
+ override def min : Long = _buckets.minBy(_._1)._1
159
+
160
+ override def max : Long = _buckets.maxBy(_._1)._1
161
+
162
+ override def sum : Long = _buckets.foldLeft(0L ) { case (a, (v, f)) => a + (v * f) }
163
+
164
+ override def count : Long = _buckets.foldLeft(0L ) { case (a, (_, f)) => a + f }
165
+
166
+ override def percentile (rank : Double ): Distribution .Percentile = ??? // percentileValues.get(rank).map(r => r.toPercentile).orNull
167
+
168
+ override def percentiles : Seq [Distribution .Percentile ] = ??? // Seq(perc.toPercentile)
169
+
170
+ override def percentilesIterator : Iterator [Distribution .Percentile ] = null
171
+
172
+ override def buckets : Seq [Distribution .Bucket ] = bucketsIterator.toSeq
173
+
174
+ override def bucketsIterator : Iterator [Distribution .Bucket ] = _buckets.iterator.map { case (v, f) => PureDistributionBucket (v, f) }
175
+ }
176
+ distribution
177
+ }
178
+
179
+ case class PureDistributionBucket (value : Long , frequency : Long ) extends Distribution .Bucket
180
+
108
181
private class MockMetricsService extends MetricsService {
109
182
var exportMetricsServiceRequest : Option [JCollection [MetricData ]] = None
110
183
var hasBeenClosed = false
0 commit comments