datapoint_test.go 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. package awsemfexporter
  4. import (
  5. "fmt"
  6. "math"
  7. "reflect"
  8. "testing"
  9. "time"
  10. "github.com/stretchr/testify/assert"
  11. "github.com/stretchr/testify/require"
  12. "go.opentelemetry.io/collector/pdata/pcommon"
  13. "go.opentelemetry.io/collector/pdata/pmetric"
  14. "go.uber.org/multierr"
  15. "go.uber.org/zap"
  16. "go.uber.org/zap/zapcore"
  17. "go.uber.org/zap/zaptest/observer"
  18. aws "github.com/open-telemetry/opentelemetry-collector-contrib/internal/aws/metrics"
  19. )
  20. type metricValueType string
  21. const (
  22. intValueType metricValueType = "int"
  23. doubleValueType metricValueType = "double"
  24. )
  25. const instrLibName = "cloudwatch-otel"
  26. func generateTestGaugeMetric(name string, valueType metricValueType) pmetric.Metrics {
  27. otelMetrics := pmetric.NewMetrics()
  28. rs := otelMetrics.ResourceMetrics().AppendEmpty()
  29. metrics := rs.ScopeMetrics().AppendEmpty().Metrics()
  30. metric := metrics.AppendEmpty()
  31. metric.SetName(name)
  32. metric.SetUnit("Count")
  33. gaugeMetric := metric.SetEmptyGauge()
  34. gaugeDatapoint := gaugeMetric.DataPoints().AppendEmpty()
  35. gaugeDatapoint.Attributes().PutStr("label1", "value1")
  36. switch valueType {
  37. case doubleValueType:
  38. gaugeDatapoint.SetDoubleValue(0.1)
  39. default:
  40. gaugeDatapoint.SetIntValue(1)
  41. }
  42. return otelMetrics
  43. }
  44. func generateTestGaugeMetricNaN(name string) pmetric.Metrics {
  45. otelMetrics := pmetric.NewMetrics()
  46. rs := otelMetrics.ResourceMetrics().AppendEmpty()
  47. metrics := rs.ScopeMetrics().AppendEmpty().Metrics()
  48. metric := metrics.AppendEmpty()
  49. metric.SetName(name)
  50. metric.SetUnit("Count")
  51. gaugeMetric := metric.SetEmptyGauge()
  52. gaugeDatapoint := gaugeMetric.DataPoints().AppendEmpty()
  53. gaugeDatapoint.Attributes().PutStr("label1", "value1")
  54. gaugeDatapoint.SetDoubleValue(math.NaN())
  55. return otelMetrics
  56. }
  57. func generateTestSumMetric(name string, valueType metricValueType) pmetric.Metrics {
  58. otelMetrics := pmetric.NewMetrics()
  59. rs := otelMetrics.ResourceMetrics().AppendEmpty()
  60. metrics := rs.ScopeMetrics().AppendEmpty().Metrics()
  61. for i := 0; i < 2; i++ {
  62. metric := metrics.AppendEmpty()
  63. metric.SetName(name)
  64. metric.SetUnit("Count")
  65. sumMetric := metric.SetEmptySum()
  66. sumMetric.SetIsMonotonic(true)
  67. sumMetric.SetAggregationTemporality(pmetric.AggregationTemporalityCumulative)
  68. sumDatapoint := sumMetric.DataPoints().AppendEmpty()
  69. sumDatapoint.Attributes().PutStr("label1", "value1")
  70. switch valueType {
  71. case doubleValueType:
  72. sumDatapoint.SetDoubleValue(float64(i) * 0.1)
  73. default:
  74. sumDatapoint.SetIntValue(int64(i))
  75. }
  76. }
  77. return otelMetrics
  78. }
  79. func generateTestHistogramMetric(name string) pmetric.Metrics {
  80. otelMetrics := pmetric.NewMetrics()
  81. rs := otelMetrics.ResourceMetrics().AppendEmpty()
  82. metrics := rs.ScopeMetrics().AppendEmpty().Metrics()
  83. metric := metrics.AppendEmpty()
  84. metric.SetName(name)
  85. metric.SetUnit("Seconds")
  86. histogramMetric := metric.SetEmptyHistogram()
  87. histogramDatapoint := histogramMetric.DataPoints().AppendEmpty()
  88. histogramDatapoint.BucketCounts().FromRaw([]uint64{5, 6, 7})
  89. histogramDatapoint.ExplicitBounds().FromRaw([]float64{0, 10})
  90. histogramDatapoint.Attributes().PutStr("label1", "value1")
  91. histogramDatapoint.SetCount(18)
  92. histogramDatapoint.SetSum(35.0)
  93. return otelMetrics
  94. }
  95. func generateTestHistogramMetricWithNaNs(name string) pmetric.Metrics {
  96. otelMetrics := pmetric.NewMetrics()
  97. rs := otelMetrics.ResourceMetrics().AppendEmpty()
  98. metrics := rs.ScopeMetrics().AppendEmpty().Metrics()
  99. metric := metrics.AppendEmpty()
  100. metric.SetName(name)
  101. metric.SetUnit("Seconds")
  102. histogramMetric := metric.SetEmptyHistogram()
  103. histogramDatapoint := histogramMetric.DataPoints().AppendEmpty()
  104. histogramDatapoint.BucketCounts().FromRaw([]uint64{5, 6, 7})
  105. histogramDatapoint.ExplicitBounds().FromRaw([]float64{0, math.NaN()})
  106. histogramDatapoint.Attributes().PutStr("label1", "value1")
  107. histogramDatapoint.SetCount(18)
  108. histogramDatapoint.SetSum(math.NaN())
  109. return otelMetrics
  110. }
  111. func generateTestExponentialHistogramMetric(name string) pmetric.Metrics {
  112. otelMetrics := pmetric.NewMetrics()
  113. rs := otelMetrics.ResourceMetrics().AppendEmpty()
  114. metrics := rs.ScopeMetrics().AppendEmpty().Metrics()
  115. metric := metrics.AppendEmpty()
  116. metric.SetName(name)
  117. metric.SetUnit("Seconds")
  118. exponentialHistogramMetric := metric.SetEmptyExponentialHistogram()
  119. exponentialHistogramDatapoint := exponentialHistogramMetric.DataPoints().AppendEmpty()
  120. exponentialHistogramDatapoint.SetCount(4)
  121. exponentialHistogramDatapoint.SetSum(0)
  122. exponentialHistogramDatapoint.SetMin(-4)
  123. exponentialHistogramDatapoint.SetMax(4)
  124. exponentialHistogramDatapoint.SetZeroCount(0)
  125. exponentialHistogramDatapoint.SetScale(1)
  126. exponentialHistogramDatapoint.Positive().SetOffset(1)
  127. exponentialHistogramDatapoint.Positive().BucketCounts().FromRaw([]uint64{
  128. 1, 0, 1,
  129. })
  130. exponentialHistogramDatapoint.Negative().SetOffset(1)
  131. exponentialHistogramDatapoint.Negative().BucketCounts().FromRaw([]uint64{
  132. 1, 0, 1,
  133. })
  134. exponentialHistogramDatapoint.Attributes().PutStr("label1", "value1")
  135. return otelMetrics
  136. }
  137. func generateTestExponentialHistogramMetricWithNaNs(name string) pmetric.Metrics {
  138. otelMetrics := pmetric.NewMetrics()
  139. rs := otelMetrics.ResourceMetrics().AppendEmpty()
  140. metrics := rs.ScopeMetrics().AppendEmpty().Metrics()
  141. metric := metrics.AppendEmpty()
  142. metric.SetName(name)
  143. metric.SetUnit("Seconds")
  144. exponentialHistogramMetric := metric.SetEmptyExponentialHistogram()
  145. exponentialHistogramDatapoint := exponentialHistogramMetric.DataPoints().AppendEmpty()
  146. exponentialHistogramDatapoint.SetCount(4)
  147. exponentialHistogramDatapoint.SetSum(math.NaN())
  148. exponentialHistogramDatapoint.SetMin(math.NaN())
  149. exponentialHistogramDatapoint.SetMax(math.NaN())
  150. exponentialHistogramDatapoint.SetZeroCount(0)
  151. exponentialHistogramDatapoint.SetScale(1)
  152. exponentialHistogramDatapoint.Positive().SetOffset(1)
  153. exponentialHistogramDatapoint.Positive().BucketCounts().FromRaw([]uint64{
  154. 1, 0, 1,
  155. })
  156. exponentialHistogramDatapoint.Negative().SetOffset(1)
  157. exponentialHistogramDatapoint.Negative().BucketCounts().FromRaw([]uint64{
  158. 1, 0, 1,
  159. })
  160. exponentialHistogramDatapoint.Attributes().PutStr("label1", "value1")
  161. return otelMetrics
  162. }
  163. func generateTestSummaryMetric(name string) pmetric.Metrics {
  164. otelMetrics := pmetric.NewMetrics()
  165. rs := otelMetrics.ResourceMetrics().AppendEmpty()
  166. metrics := rs.ScopeMetrics().AppendEmpty().Metrics()
  167. for i := 0; i < 2; i++ {
  168. metric := metrics.AppendEmpty()
  169. metric.SetName(name)
  170. metric.SetUnit("Seconds")
  171. summaryMetric := metric.SetEmptySummary()
  172. summaryDatapoint := summaryMetric.DataPoints().AppendEmpty()
  173. summaryDatapoint.Attributes().PutStr("label1", "value1")
  174. summaryDatapoint.SetCount(uint64(5 * i))
  175. summaryDatapoint.SetSum(float64(15.0 * i))
  176. firstQuantile := summaryDatapoint.QuantileValues().AppendEmpty()
  177. firstQuantile.SetQuantile(0.0)
  178. firstQuantile.SetValue(1)
  179. secondQuantile := summaryDatapoint.QuantileValues().AppendEmpty()
  180. secondQuantile.SetQuantile(100.0)
  181. secondQuantile.SetValue(5)
  182. }
  183. return otelMetrics
  184. }
  185. func generateTestSummaryMetricWithNaN(name string) pmetric.Metrics {
  186. otelMetrics := pmetric.NewMetrics()
  187. rs := otelMetrics.ResourceMetrics().AppendEmpty()
  188. metrics := rs.ScopeMetrics().AppendEmpty().Metrics()
  189. for i := 0; i < 2; i++ {
  190. metric := metrics.AppendEmpty()
  191. metric.SetName(name)
  192. metric.SetUnit("Seconds")
  193. summaryMetric := metric.SetEmptySummary()
  194. summaryDatapoint := summaryMetric.DataPoints().AppendEmpty()
  195. summaryDatapoint.Attributes().PutStr("label1", "value1")
  196. summaryDatapoint.SetCount(uint64(5 * i))
  197. summaryDatapoint.SetSum(math.NaN())
  198. firstQuantile := summaryDatapoint.QuantileValues().AppendEmpty()
  199. firstQuantile.SetQuantile(math.NaN())
  200. firstQuantile.SetValue(math.NaN())
  201. secondQuantile := summaryDatapoint.QuantileValues().AppendEmpty()
  202. secondQuantile.SetQuantile(math.NaN())
  203. secondQuantile.SetValue(math.NaN())
  204. }
  205. return otelMetrics
  206. }
  207. func generateOtelTestMetrics(generatedOtelMetrics ...pmetric.Metrics) pmetric.Metrics {
  208. finalOtelMetrics := pmetric.NewMetrics()
  209. rs := finalOtelMetrics.ResourceMetrics().AppendEmpty()
  210. finalMetrics := rs.ScopeMetrics().AppendEmpty().Metrics()
  211. for _, generatedOtelMetric := range generatedOtelMetrics {
  212. generatedMetrics := generatedOtelMetric.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics()
  213. for i := 0; i < generatedMetrics.Len(); i++ {
  214. generatedMetric := generatedMetrics.At(i)
  215. finalMetric := finalMetrics.AppendEmpty()
  216. generatedMetric.CopyTo(finalMetric)
  217. }
  218. }
  219. return finalOtelMetrics
  220. }
  221. func generateDeltaMetricMetadata(adjustToDelta bool, metricName string, retainInitialValueForDelta bool) deltaMetricMetadata {
  222. return deltaMetricMetadata{
  223. adjustToDelta: adjustToDelta,
  224. metricName: metricName,
  225. logGroup: "log-group",
  226. logStream: "log-stream",
  227. namespace: "namespace",
  228. retainInitialValueForDelta: retainInitialValueForDelta,
  229. }
  230. }
  231. func setupEmfCalculators() *emfCalculators {
  232. return &emfCalculators{
  233. summary: aws.NewMetricCalculator(calculateSummaryDelta),
  234. delta: aws.NewFloat64DeltaCalculator(),
  235. }
  236. }
  237. func shutdownEmfCalculators(c *emfCalculators) error {
  238. var errs error
  239. errs = multierr.Append(errs, c.delta.Shutdown())
  240. return multierr.Append(errs, c.summary.Shutdown())
  241. }
  242. func TestIsStaleOrNaN_NumberDataPointSlice(t *testing.T) {
  243. testCases := []struct {
  244. name string
  245. metricName string
  246. metricValue any
  247. expectedAssert assert.BoolAssertionFunc
  248. setFlagsFunc func(point pmetric.NumberDataPoint) pmetric.NumberDataPoint
  249. }{
  250. {
  251. name: "nan",
  252. metricValue: math.NaN(),
  253. metricName: "NaN",
  254. expectedAssert: assert.True,
  255. },
  256. {
  257. name: "valid float",
  258. metricValue: 0.4,
  259. metricName: "floaty mc-float-face",
  260. expectedAssert: assert.False,
  261. },
  262. {
  263. name: "data point flag set",
  264. metricValue: 0.4,
  265. metricName: "floaty mc-float-face part two",
  266. expectedAssert: assert.True,
  267. setFlagsFunc: func(point pmetric.NumberDataPoint) pmetric.NumberDataPoint {
  268. point.SetFlags(pmetric.DefaultDataPointFlags.WithNoRecordedValue(true))
  269. return point
  270. },
  271. },
  272. }
  273. for _, tc := range testCases {
  274. t.Run(tc.name, func(t *testing.T) {
  275. // Given the number datapoint (including Sum and Gauge OTEL metric type) with data type as int or double
  276. numberDPS := pmetric.NewNumberDataPointSlice()
  277. numberDP := numberDPS.AppendEmpty()
  278. if tc.setFlagsFunc != nil {
  279. tc.setFlagsFunc(numberDP)
  280. }
  281. switch v := tc.metricValue.(type) {
  282. case int64:
  283. numberDP.SetIntValue(v)
  284. case float64:
  285. numberDP.SetDoubleValue(v)
  286. }
  287. numberDatapointSlice := numberDataPointSlice{deltaMetricMetadata{}, numberDPS}
  288. isStaleOrNan, _ := numberDatapointSlice.IsStaleOrNaN(0)
  289. tc.expectedAssert(t, isStaleOrNan)
  290. })
  291. }
  292. }
  293. func TestCalculateDeltaDatapoints_NumberDataPointSlice(t *testing.T) {
  294. emfCalcs := setupEmfCalculators()
  295. defer require.NoError(t, shutdownEmfCalculators(emfCalcs))
  296. for _, retainInitialValueOfDeltaMetric := range []bool{true, false} {
  297. testCases := []struct {
  298. name string
  299. adjustToDelta bool
  300. metricName string
  301. metricValue any
  302. expectedDatapoint dataPoint
  303. expectedRetained bool
  304. }{
  305. {
  306. name: fmt.Sprintf("Float data type with 1st delta calculation retainInitialValueOfDeltaMetric=%t", retainInitialValueOfDeltaMetric),
  307. adjustToDelta: true,
  308. metricValue: 0.4,
  309. metricName: "double",
  310. expectedDatapoint: dataPoint{
  311. name: "double",
  312. value: 0.4,
  313. labels: map[string]string{oTellibDimensionKey: instrLibName, "label1": "value1"},
  314. },
  315. expectedRetained: retainInitialValueOfDeltaMetric,
  316. },
  317. {
  318. name: "Float data type with 2nd delta calculation",
  319. adjustToDelta: true,
  320. metricName: "double",
  321. metricValue: 0.8,
  322. expectedDatapoint: dataPoint{
  323. name: "double",
  324. value: 0.4,
  325. labels: map[string]string{oTellibDimensionKey: instrLibName, "label1": "value1"},
  326. },
  327. expectedRetained: true,
  328. },
  329. {
  330. name: "Double data type without delta calculation",
  331. adjustToDelta: false,
  332. metricName: "double",
  333. metricValue: 0.5,
  334. expectedDatapoint: dataPoint{
  335. name: "double",
  336. value: 0.5,
  337. labels: map[string]string{oTellibDimensionKey: instrLibName, "label1": "value1"},
  338. },
  339. expectedRetained: true,
  340. },
  341. {
  342. name: "Int data type with 1st delta calculation",
  343. adjustToDelta: true,
  344. metricName: "int",
  345. metricValue: int64(-17),
  346. expectedDatapoint: dataPoint{
  347. name: "int",
  348. value: float64(-17),
  349. labels: map[string]string{oTellibDimensionKey: instrLibName, "label1": "value1"},
  350. },
  351. expectedRetained: retainInitialValueOfDeltaMetric,
  352. },
  353. {
  354. name: "Int data type with 2nd delta calculation",
  355. adjustToDelta: true,
  356. metricName: "int",
  357. metricValue: int64(1),
  358. expectedDatapoint: dataPoint{
  359. name: "int",
  360. value: float64(18),
  361. labels: map[string]string{oTellibDimensionKey: instrLibName, "label1": "value1"},
  362. },
  363. expectedRetained: true,
  364. },
  365. {
  366. name: "Int data type without delta calculation",
  367. adjustToDelta: false,
  368. metricName: "int",
  369. metricValue: int64(10),
  370. expectedDatapoint: dataPoint{
  371. name: "int",
  372. value: float64(10),
  373. labels: map[string]string{oTellibDimensionKey: instrLibName, "label1": "value1"},
  374. },
  375. expectedRetained: true,
  376. },
  377. }
  378. for _, tc := range testCases {
  379. t.Run(tc.name, func(t *testing.T) {
  380. // Given the number datapoint (including Sum and Gauge OTEL metric type) with data type as int or double
  381. numberDPS := pmetric.NewNumberDataPointSlice()
  382. numberDP := numberDPS.AppendEmpty()
  383. numberDP.Attributes().PutStr("label1", "value1")
  384. switch v := tc.metricValue.(type) {
  385. case int64:
  386. numberDP.SetIntValue(v)
  387. case float64:
  388. numberDP.SetDoubleValue(v)
  389. }
  390. dmd := generateDeltaMetricMetadata(tc.adjustToDelta, tc.metricName, retainInitialValueOfDeltaMetric)
  391. numberDatapointSlice := numberDataPointSlice{dmd, numberDPS}
  392. // When calculate the delta datapoints for number datapoint
  393. dps, retained := numberDatapointSlice.CalculateDeltaDatapoints(0, instrLibName, false, emfCalcs)
  394. assert.Equal(t, 1, numberDatapointSlice.Len())
  395. assert.Equal(t, tc.expectedRetained, retained)
  396. if retained {
  397. assert.Equal(t, tc.expectedDatapoint.name, dps[0].name)
  398. assert.Equal(t, tc.expectedDatapoint.labels, dps[0].labels)
  399. // Asserting the delta is within 0.002 with the following datapoint
  400. assert.InDelta(t, tc.expectedDatapoint.value, dps[0].value, 0.002)
  401. }
  402. })
  403. }
  404. }
  405. }
  406. func TestCalculateDeltaDatapoints_HistogramDataPointSlice(t *testing.T) {
  407. dmd := generateDeltaMetricMetadata(false, "foo", false)
  408. testCases := []struct {
  409. name string
  410. histogramDPS pmetric.HistogramDataPointSlice
  411. expectedDatapoint dataPoint
  412. }{
  413. {
  414. name: "Histogram with min and max",
  415. histogramDPS: func() pmetric.HistogramDataPointSlice {
  416. histogramDPS := pmetric.NewHistogramDataPointSlice()
  417. histogramDP := histogramDPS.AppendEmpty()
  418. histogramDP.SetCount(uint64(17))
  419. histogramDP.SetSum(17.13)
  420. histogramDP.SetMin(10)
  421. histogramDP.SetMax(30)
  422. histogramDP.Attributes().PutStr("label1", "value1")
  423. return histogramDPS
  424. }(),
  425. expectedDatapoint: dataPoint{
  426. name: "foo",
  427. value: &cWMetricStats{Sum: 17.13, Count: 17, Min: 10, Max: 30},
  428. labels: map[string]string{oTellibDimensionKey: instrLibName, "label1": "value1"},
  429. },
  430. },
  431. {
  432. name: "Histogram without min and max",
  433. histogramDPS: func() pmetric.HistogramDataPointSlice {
  434. histogramDPS := pmetric.NewHistogramDataPointSlice()
  435. histogramDP := histogramDPS.AppendEmpty()
  436. histogramDP.SetCount(uint64(17))
  437. histogramDP.SetSum(17.13)
  438. histogramDP.Attributes().PutStr("label1", "value1")
  439. return histogramDPS
  440. }(),
  441. expectedDatapoint: dataPoint{
  442. name: "foo",
  443. value: &cWMetricStats{Sum: 17.13, Count: 17, Min: 0, Max: 0},
  444. labels: map[string]string{oTellibDimensionKey: instrLibName, "label1": "value1"},
  445. },
  446. },
  447. {
  448. name: "Histogram with buckets and bounds",
  449. histogramDPS: func() pmetric.HistogramDataPointSlice {
  450. histogramDPS := pmetric.NewHistogramDataPointSlice()
  451. histogramDP := histogramDPS.AppendEmpty()
  452. histogramDP.SetCount(uint64(17))
  453. histogramDP.SetSum(17.13)
  454. histogramDP.BucketCounts().FromRaw([]uint64{1, 2, 3})
  455. histogramDP.ExplicitBounds().FromRaw([]float64{1, 2, 3})
  456. histogramDP.Attributes().PutStr("label1", "value1")
  457. return histogramDPS
  458. }(),
  459. expectedDatapoint: dataPoint{
  460. name: "foo",
  461. value: &cWMetricStats{Sum: 17.13, Count: 17, Min: 0, Max: 0},
  462. labels: map[string]string{oTellibDimensionKey: instrLibName, "label1": "value1"},
  463. },
  464. },
  465. }
  466. for _, tc := range testCases {
  467. t.Run(tc.name, func(_ *testing.T) {
  468. // Given the histogram datapoints
  469. histogramDatapointSlice := histogramDataPointSlice{dmd, tc.histogramDPS}
  470. emfCalcs := setupEmfCalculators()
  471. defer require.NoError(t, shutdownEmfCalculators(emfCalcs))
  472. // When calculate the delta datapoints for histograms
  473. dps, retained := histogramDatapointSlice.CalculateDeltaDatapoints(0, instrLibName, false, emfCalcs)
  474. // Then receiving the following datapoint with an expected length
  475. assert.True(t, retained)
  476. assert.Equal(t, 1, histogramDatapointSlice.Len())
  477. assert.Equal(t, tc.expectedDatapoint, dps[0])
  478. })
  479. }
  480. }
  481. func TestIsStaleOrNaN_HistogramDataPointSlice(t *testing.T) {
  482. testCases := []struct {
  483. name string
  484. histogramDPS pmetric.HistogramDataPointSlice
  485. boolAssertFunc assert.BoolAssertionFunc
  486. setFlagsFunc func(point pmetric.HistogramDataPoint) pmetric.HistogramDataPoint
  487. }{
  488. {
  489. name: "Histogram with all NaNs",
  490. histogramDPS: func() pmetric.HistogramDataPointSlice {
  491. histogramDPS := pmetric.NewHistogramDataPointSlice()
  492. histogramDP := histogramDPS.AppendEmpty()
  493. histogramDP.SetCount(uint64(17))
  494. histogramDP.SetSum(math.NaN())
  495. histogramDP.SetMin(math.NaN())
  496. histogramDP.SetMax(math.NaN())
  497. histogramDP.Attributes().PutStr("label1", "value1")
  498. return histogramDPS
  499. }(),
  500. boolAssertFunc: assert.True,
  501. },
  502. {
  503. name: "Histogram with NaN Sum",
  504. histogramDPS: func() pmetric.HistogramDataPointSlice {
  505. histogramDPS := pmetric.NewHistogramDataPointSlice()
  506. histogramDP := histogramDPS.AppendEmpty()
  507. histogramDP.SetCount(uint64(17))
  508. histogramDP.SetSum(math.NaN())
  509. histogramDP.SetMin(1234)
  510. histogramDP.SetMax(1234)
  511. histogramDP.Attributes().PutStr("label1", "value1")
  512. return histogramDPS
  513. }(),
  514. boolAssertFunc: assert.True,
  515. },
  516. {
  517. name: "Histogram with NaN Min",
  518. histogramDPS: func() pmetric.HistogramDataPointSlice {
  519. histogramDPS := pmetric.NewHistogramDataPointSlice()
  520. histogramDP := histogramDPS.AppendEmpty()
  521. histogramDP.SetCount(uint64(17))
  522. histogramDP.SetSum(123)
  523. histogramDP.SetMin(math.NaN())
  524. histogramDP.SetMax(123)
  525. histogramDP.Attributes().PutStr("label1", "value1")
  526. return histogramDPS
  527. }(),
  528. boolAssertFunc: assert.True,
  529. },
  530. {
  531. name: "Histogram with nan Max",
  532. histogramDPS: func() pmetric.HistogramDataPointSlice {
  533. histogramDPS := pmetric.NewHistogramDataPointSlice()
  534. histogramDP := histogramDPS.AppendEmpty()
  535. histogramDP.SetCount(uint64(17))
  536. histogramDP.SetSum(123)
  537. histogramDP.SetMin(123)
  538. histogramDP.SetMax(math.NaN())
  539. histogramDP.Attributes().PutStr("label1", "value1")
  540. return histogramDPS
  541. }(),
  542. boolAssertFunc: assert.True,
  543. },
  544. {
  545. name: "Histogram with min and max",
  546. histogramDPS: func() pmetric.HistogramDataPointSlice {
  547. histogramDPS := pmetric.NewHistogramDataPointSlice()
  548. histogramDP := histogramDPS.AppendEmpty()
  549. histogramDP.SetCount(uint64(17))
  550. histogramDP.SetSum(17.13)
  551. histogramDP.SetMin(10)
  552. histogramDP.SetMax(30)
  553. histogramDP.Attributes().PutStr("label1", "value1")
  554. return histogramDPS
  555. }(),
  556. boolAssertFunc: assert.False,
  557. },
  558. {
  559. name: "Histogram with no NaNs",
  560. histogramDPS: func() pmetric.HistogramDataPointSlice {
  561. histogramDPS := pmetric.NewHistogramDataPointSlice()
  562. histogramDP := histogramDPS.AppendEmpty()
  563. histogramDP.SetCount(uint64(17))
  564. histogramDP.SetSum(17.13)
  565. histogramDP.SetMin(10)
  566. histogramDP.SetMax(30)
  567. histogramDP.Attributes().PutStr("label1", "value1")
  568. return histogramDPS
  569. }(),
  570. boolAssertFunc: assert.True,
  571. setFlagsFunc: func(point pmetric.HistogramDataPoint) pmetric.HistogramDataPoint {
  572. point.SetFlags(pmetric.DefaultDataPointFlags.WithNoRecordedValue(true))
  573. return point
  574. },
  575. },
  576. }
  577. for _, tc := range testCases {
  578. t.Run(tc.name, func(_ *testing.T) {
  579. // Given the histogram datapoints
  580. histogramDatapointSlice := histogramDataPointSlice{deltaMetricMetadata{}, tc.histogramDPS}
  581. if tc.setFlagsFunc != nil {
  582. tc.setFlagsFunc(histogramDatapointSlice.At(0))
  583. }
  584. isStaleOrNan, _ := histogramDatapointSlice.IsStaleOrNaN(0)
  585. tc.boolAssertFunc(t, isStaleOrNan)
  586. })
  587. }
  588. }
  589. func TestCalculateDeltaDatapoints_ExponentialHistogramDataPointSlice(t *testing.T) {
  590. dmd := generateDeltaMetricMetadata(false, "foo", false)
  591. testCases := []struct {
  592. name string
  593. histogramDPS pmetric.ExponentialHistogramDataPointSlice
  594. expectedDatapoint dataPoint
  595. }{
  596. {
  597. name: "Exponential histogram with min and max",
  598. histogramDPS: func() pmetric.ExponentialHistogramDataPointSlice {
  599. histogramDPS := pmetric.NewExponentialHistogramDataPointSlice()
  600. histogramDP := histogramDPS.AppendEmpty()
  601. histogramDP.SetCount(uint64(17))
  602. histogramDP.SetSum(17.13)
  603. histogramDP.SetMin(10)
  604. histogramDP.SetMax(30)
  605. histogramDP.Attributes().PutStr("label1", "value1")
  606. return histogramDPS
  607. }(),
  608. expectedDatapoint: dataPoint{
  609. name: "foo",
  610. value: &cWMetricHistogram{Values: []float64{}, Counts: []float64{}, Sum: 17.13, Count: 17, Min: 10, Max: 30},
  611. labels: map[string]string{oTellibDimensionKey: instrLibName, "label1": "value1"},
  612. },
  613. },
  614. {
  615. name: "Exponential histogram without min and max",
  616. histogramDPS: func() pmetric.ExponentialHistogramDataPointSlice {
  617. histogramDPS := pmetric.NewExponentialHistogramDataPointSlice()
  618. histogramDP := histogramDPS.AppendEmpty()
  619. histogramDP.SetCount(uint64(17))
  620. histogramDP.SetSum(17.13)
  621. histogramDP.Attributes().PutStr("label1", "value1")
  622. return histogramDPS
  623. }(),
  624. expectedDatapoint: dataPoint{
  625. name: "foo",
  626. value: &cWMetricHistogram{Values: []float64{}, Counts: []float64{}, Sum: 17.13, Count: 17, Min: 0, Max: 0},
  627. labels: map[string]string{oTellibDimensionKey: instrLibName, "label1": "value1"},
  628. },
  629. },
  630. {
  631. name: "Exponential histogram with buckets",
  632. histogramDPS: func() pmetric.ExponentialHistogramDataPointSlice {
  633. histogramDPS := pmetric.NewExponentialHistogramDataPointSlice()
  634. histogramDP := histogramDPS.AppendEmpty()
  635. histogramDP.Positive().BucketCounts().FromRaw([]uint64{1, 2, 3})
  636. histogramDP.SetZeroCount(4)
  637. histogramDP.Negative().BucketCounts().FromRaw([]uint64{1, 2, 3})
  638. histogramDP.Attributes().PutStr("label1", "value1")
  639. return histogramDPS
  640. }(),
  641. expectedDatapoint: dataPoint{
  642. name: "foo",
  643. value: &cWMetricHistogram{Values: []float64{1.5, 3, 6, 0, -1.5, -3, -6}, Counts: []float64{1, 2, 3, 4, 1, 2, 3}},
  644. labels: map[string]string{oTellibDimensionKey: instrLibName, "label1": "value1"},
  645. },
  646. },
  647. {
  648. name: "Exponential histogram with different scale/offset/labels",
  649. histogramDPS: func() pmetric.ExponentialHistogramDataPointSlice {
  650. histogramDPS := pmetric.NewExponentialHistogramDataPointSlice()
  651. histogramDP := histogramDPS.AppendEmpty()
  652. histogramDP.SetScale(-1)
  653. histogramDP.Positive().SetOffset(-1)
  654. histogramDP.Positive().BucketCounts().FromRaw([]uint64{1, 2, 3})
  655. histogramDP.SetZeroCount(4)
  656. histogramDP.Negative().SetOffset(-1)
  657. histogramDP.Negative().BucketCounts().FromRaw([]uint64{1, 2, 3})
  658. histogramDP.Attributes().PutStr("label1", "value1")
  659. histogramDP.Attributes().PutStr("label2", "value2")
  660. return histogramDPS
  661. }(),
  662. expectedDatapoint: dataPoint{
  663. name: "foo",
  664. value: &cWMetricHistogram{Values: []float64{0.625, 2.5, 10, 0, -0.625, -2.5, -10}, Counts: []float64{1, 2, 3, 4, 1, 2, 3}},
  665. labels: map[string]string{oTellibDimensionKey: instrLibName, "label1": "value1", "label2": "value2"},
  666. },
  667. },
  668. }
  669. for _, tc := range testCases {
  670. t.Run(tc.name, func(_ *testing.T) {
  671. // Given the histogram datapoints
  672. exponentialHistogramDatapointSlice := exponentialHistogramDataPointSlice{dmd, tc.histogramDPS}
  673. emfCalcs := setupEmfCalculators()
  674. defer require.NoError(t, shutdownEmfCalculators(emfCalcs))
  675. // When calculate the delta datapoints for histograms
  676. dps, retained := exponentialHistogramDatapointSlice.CalculateDeltaDatapoints(0, instrLibName, false, emfCalcs)
  677. // Then receiving the following datapoint with an expected length
  678. assert.True(t, retained)
  679. assert.Equal(t, 1, exponentialHistogramDatapointSlice.Len())
  680. assert.Equal(t, tc.expectedDatapoint, dps[0])
  681. })
  682. }
  683. }
  684. func TestIsStaleOrNaN_ExponentialHistogramDataPointSlice(t *testing.T) {
  685. testCases := []struct {
  686. name string
  687. histogramDPS pmetric.ExponentialHistogramDataPointSlice
  688. boolAssertFunc assert.BoolAssertionFunc
  689. setFlagsFunc func(point pmetric.ExponentialHistogramDataPoint) pmetric.ExponentialHistogramDataPoint
  690. }{
  691. {
  692. name: "Exponential histogram with non NaNs",
  693. histogramDPS: func() pmetric.ExponentialHistogramDataPointSlice {
  694. histogramDPS := pmetric.NewExponentialHistogramDataPointSlice()
  695. histogramDP := histogramDPS.AppendEmpty()
  696. histogramDP.SetCount(uint64(17))
  697. histogramDP.SetSum(17.13)
  698. histogramDP.SetMin(10)
  699. histogramDP.SetMax(30)
  700. histogramDP.Attributes().PutStr("label1", "value1")
  701. return histogramDPS
  702. }(),
  703. boolAssertFunc: assert.False,
  704. },
  705. {
  706. name: "Exponential histogram with all possible NaN",
  707. histogramDPS: func() pmetric.ExponentialHistogramDataPointSlice {
  708. histogramDPS := pmetric.NewExponentialHistogramDataPointSlice()
  709. histogramDP := histogramDPS.AppendEmpty()
  710. histogramDP.SetCount(uint64(17))
  711. histogramDP.SetSum(math.NaN())
  712. histogramDP.SetMin(math.NaN())
  713. histogramDP.SetMax(math.NaN())
  714. histogramDP.Attributes().PutStr("label1", "value1")
  715. return histogramDPS
  716. }(),
  717. boolAssertFunc: assert.True,
  718. },
  719. {
  720. name: "Exponential histogram with NaN Sum",
  721. histogramDPS: func() pmetric.ExponentialHistogramDataPointSlice {
  722. histogramDPS := pmetric.NewExponentialHistogramDataPointSlice()
  723. histogramDP := histogramDPS.AppendEmpty()
  724. histogramDP.SetCount(uint64(17))
  725. histogramDP.SetSum(math.NaN())
  726. histogramDP.SetMin(1245)
  727. histogramDP.SetMax(1234556)
  728. histogramDP.Attributes().PutStr("label1", "value1")
  729. return histogramDPS
  730. }(),
  731. boolAssertFunc: assert.True,
  732. },
  733. {
  734. name: "Exponential histogram with NaN Min",
  735. histogramDPS: func() pmetric.ExponentialHistogramDataPointSlice {
  736. histogramDPS := pmetric.NewExponentialHistogramDataPointSlice()
  737. histogramDP := histogramDPS.AppendEmpty()
  738. histogramDP.SetCount(uint64(17))
  739. histogramDP.SetSum(1255)
  740. histogramDP.SetMin(math.NaN())
  741. histogramDP.SetMax(12545)
  742. histogramDP.Attributes().PutStr("label1", "value1")
  743. return histogramDPS
  744. }(),
  745. boolAssertFunc: assert.True,
  746. },
  747. {
  748. name: "Exponential histogram with NaN Max",
  749. histogramDPS: func() pmetric.ExponentialHistogramDataPointSlice {
  750. histogramDPS := pmetric.NewExponentialHistogramDataPointSlice()
  751. histogramDP := histogramDPS.AppendEmpty()
  752. histogramDP.SetCount(uint64(17))
  753. histogramDP.SetSum(512444)
  754. histogramDP.SetMin(123)
  755. histogramDP.SetMax(math.NaN())
  756. histogramDP.Attributes().PutStr("label1", "value1")
  757. return histogramDPS
  758. }(),
  759. boolAssertFunc: assert.True,
  760. },
  761. {
  762. name: "Exponential histogram with NaNs",
  763. histogramDPS: func() pmetric.ExponentialHistogramDataPointSlice {
  764. histogramDPS := pmetric.NewExponentialHistogramDataPointSlice()
  765. histogramDP := histogramDPS.AppendEmpty()
  766. histogramDP.SetCount(uint64(17))
  767. histogramDP.SetSum(math.NaN())
  768. histogramDP.SetMin(math.NaN())
  769. histogramDP.SetMax(math.NaN())
  770. histogramDP.Attributes().PutStr("label1", "value1")
  771. return histogramDPS
  772. }(),
  773. boolAssertFunc: assert.True,
  774. },
  775. {
  776. name: "Exponential histogram with set flag func",
  777. histogramDPS: func() pmetric.ExponentialHistogramDataPointSlice {
  778. histogramDPS := pmetric.NewExponentialHistogramDataPointSlice()
  779. histogramDP := histogramDPS.AppendEmpty()
  780. histogramDP.SetCount(uint64(17))
  781. histogramDP.SetSum(17.13)
  782. histogramDP.SetMin(10)
  783. histogramDP.SetMax(30)
  784. histogramDP.Attributes().PutStr("label1", "value1")
  785. return histogramDPS
  786. }(),
  787. boolAssertFunc: assert.True,
  788. setFlagsFunc: func(point pmetric.ExponentialHistogramDataPoint) pmetric.ExponentialHistogramDataPoint {
  789. point.SetFlags(pmetric.DefaultDataPointFlags.WithNoRecordedValue(true))
  790. return point
  791. },
  792. },
  793. }
  794. for _, tc := range testCases {
  795. t.Run(tc.name, func(_ *testing.T) {
  796. // Given the histogram datapoints
  797. exponentialHistogramDatapointSlice := exponentialHistogramDataPointSlice{deltaMetricMetadata{}, tc.histogramDPS}
  798. if tc.setFlagsFunc != nil {
  799. tc.setFlagsFunc(exponentialHistogramDatapointSlice.At(0))
  800. }
  801. isStaleOrNaN, _ := exponentialHistogramDatapointSlice.IsStaleOrNaN(0)
  802. // When calculate the delta datapoints for histograms
  803. tc.boolAssertFunc(t, isStaleOrNaN)
  804. })
  805. }
  806. }
  807. func TestCalculateDeltaDatapoints_SummaryDataPointSlice(t *testing.T) {
  808. emfCalcs := setupEmfCalculators()
  809. defer require.NoError(t, shutdownEmfCalculators(emfCalcs))
  810. for _, retainInitialValueOfDeltaMetric := range []bool{true, false} {
  811. dmd := generateDeltaMetricMetadata(true, "foo", retainInitialValueOfDeltaMetric)
  812. testCases := []struct {
  813. name string
  814. summaryMetricValue map[string]any
  815. expectedDatapoint []dataPoint
  816. expectedRetained bool
  817. }{
  818. {
  819. name: fmt.Sprintf("Detailed summary with 1st delta sum count calculation retainInitialValueOfDeltaMetric=%t", retainInitialValueOfDeltaMetric),
  820. summaryMetricValue: map[string]any{"sum": float64(17.3), "count": uint64(17), "firstQuantile": float64(1), "secondQuantile": float64(5)},
  821. expectedDatapoint: []dataPoint{
  822. {name: fmt.Sprint("foo", summarySumSuffix), value: float64(17.3), labels: map[string]string{"label1": "value1"}},
  823. {name: fmt.Sprint("foo", summaryCountSuffix), value: uint64(17), labels: map[string]string{"label1": "value1"}},
  824. {name: "foo", value: float64(1), labels: map[string]string{"label1": "value1", "quantile": "0"}},
  825. {name: "foo", value: float64(5), labels: map[string]string{"label1": "value1", "quantile": "100"}},
  826. },
  827. expectedRetained: retainInitialValueOfDeltaMetric,
  828. },
  829. {
  830. name: "Detailed summary with 2nd delta sum count calculation",
  831. summaryMetricValue: map[string]any{"sum": float64(100), "count": uint64(25), "firstQuantile": float64(1), "secondQuantile": float64(5)},
  832. expectedDatapoint: []dataPoint{
  833. {name: fmt.Sprint("foo", summarySumSuffix), value: float64(82.7), labels: map[string]string{"label1": "value1"}},
  834. {name: fmt.Sprint("foo", summaryCountSuffix), value: uint64(8), labels: map[string]string{"label1": "value1"}},
  835. {name: "foo", value: float64(1), labels: map[string]string{"label1": "value1", "quantile": "0"}},
  836. {name: "foo", value: float64(5), labels: map[string]string{"label1": "value1", "quantile": "100"}},
  837. },
  838. expectedRetained: true,
  839. },
  840. {
  841. name: "Detailed summary with 3rd delta sum count calculation",
  842. summaryMetricValue: map[string]any{"sum": float64(120), "count": uint64(26), "firstQuantile": float64(1), "secondQuantile": float64(5)},
  843. expectedDatapoint: []dataPoint{
  844. {name: fmt.Sprint("foo", summarySumSuffix), value: float64(20), labels: map[string]string{"label1": "value1"}},
  845. {name: fmt.Sprint("foo", summaryCountSuffix), value: uint64(1), labels: map[string]string{"label1": "value1"}},
  846. {name: "foo", value: float64(1), labels: map[string]string{"label1": "value1", "quantile": "0"}},
  847. {name: "foo", value: float64(5), labels: map[string]string{"label1": "value1", "quantile": "100"}},
  848. },
  849. expectedRetained: true,
  850. },
  851. }
  852. for _, tc := range testCases {
  853. t.Run(tc.name, func(t *testing.T) {
  854. // Given the summary datapoints with quantile 0, quantile 100, sum and count
  855. summaryDPS := pmetric.NewSummaryDataPointSlice()
  856. summaryDP := summaryDPS.AppendEmpty()
  857. summaryDP.SetSum(tc.summaryMetricValue["sum"].(float64))
  858. summaryDP.SetCount(tc.summaryMetricValue["count"].(uint64))
  859. summaryDP.Attributes().PutStr("label1", "value1")
  860. summaryDP.QuantileValues().EnsureCapacity(2)
  861. firstQuantileValue := summaryDP.QuantileValues().AppendEmpty()
  862. firstQuantileValue.SetQuantile(0)
  863. firstQuantileValue.SetValue(tc.summaryMetricValue["firstQuantile"].(float64))
  864. secondQuantileValue := summaryDP.QuantileValues().AppendEmpty()
  865. secondQuantileValue.SetQuantile(100)
  866. secondQuantileValue.SetValue(tc.summaryMetricValue["secondQuantile"].(float64))
  867. summaryDatapointSlice := summaryDataPointSlice{dmd, summaryDPS}
  868. // When calculate the delta datapoints for sum and count in summary
  869. dps, retained := summaryDatapointSlice.CalculateDeltaDatapoints(0, "", true, emfCalcs)
  870. // Then receiving the following datapoint with an expected length
  871. assert.Equal(t, tc.expectedRetained, retained)
  872. assert.Equal(t, 1, summaryDatapointSlice.Len())
  873. if retained {
  874. assert.Len(t, dps, 4)
  875. for i, dp := range dps {
  876. assert.Equal(t, tc.expectedDatapoint[i].labels, dp.labels)
  877. assert.InDelta(t, tc.expectedDatapoint[i].value, dp.value, 0.002)
  878. }
  879. }
  880. })
  881. }
  882. }
  883. }
  884. func TestIsStaleOrNaN_SummaryDataPointSlice(t *testing.T) {
  885. type qMetricObject struct {
  886. value float64
  887. quantile float64
  888. }
  889. type quantileTestObj struct {
  890. sum float64
  891. count uint64
  892. qMetrics []qMetricObject
  893. }
  894. testCases := []struct {
  895. name string
  896. summaryMetricValue quantileTestObj
  897. expectedBoolAssert assert.BoolAssertionFunc
  898. setFlagsFunc func(point pmetric.SummaryDataPoint) pmetric.SummaryDataPoint
  899. }{
  900. {
  901. name: "summary with no nan values",
  902. summaryMetricValue: quantileTestObj{
  903. sum: 17.3,
  904. count: 17,
  905. qMetrics: []qMetricObject{
  906. {
  907. value: 1,
  908. quantile: 0.5,
  909. },
  910. {
  911. value: 5,
  912. quantile: 2.0,
  913. },
  914. },
  915. },
  916. expectedBoolAssert: assert.False,
  917. },
  918. {
  919. name: "Summary with nan sum",
  920. summaryMetricValue: quantileTestObj{
  921. sum: math.NaN(),
  922. count: 17,
  923. qMetrics: []qMetricObject{
  924. {
  925. value: 1,
  926. quantile: 0.5,
  927. },
  928. {
  929. value: 5,
  930. quantile: 2.0,
  931. },
  932. },
  933. },
  934. expectedBoolAssert: assert.True,
  935. },
  936. {
  937. name: "Summary with no recorded value flag set to true",
  938. summaryMetricValue: quantileTestObj{
  939. sum: 1245.65,
  940. count: 17,
  941. qMetrics: []qMetricObject{
  942. {
  943. value: 1,
  944. quantile: 0.5,
  945. },
  946. {
  947. value: 5,
  948. quantile: 2.0,
  949. },
  950. },
  951. },
  952. expectedBoolAssert: assert.True,
  953. setFlagsFunc: func(point pmetric.SummaryDataPoint) pmetric.SummaryDataPoint {
  954. point.SetFlags(pmetric.DefaultDataPointFlags.WithNoRecordedValue(true))
  955. return point
  956. },
  957. },
  958. {
  959. name: "Summary with nan quantile value",
  960. summaryMetricValue: quantileTestObj{
  961. sum: 1245.65,
  962. count: 17,
  963. qMetrics: []qMetricObject{
  964. {
  965. value: 1,
  966. quantile: 0.5,
  967. },
  968. {
  969. value: math.NaN(),
  970. quantile: 2.0,
  971. },
  972. },
  973. },
  974. expectedBoolAssert: assert.True,
  975. },
  976. {
  977. name: "Summary with nan quantile",
  978. summaryMetricValue: quantileTestObj{
  979. sum: 1245.65,
  980. count: 17,
  981. qMetrics: []qMetricObject{
  982. {
  983. value: 1,
  984. quantile: 0.5,
  985. },
  986. {
  987. value: 7.8,
  988. quantile: math.NaN(),
  989. },
  990. },
  991. },
  992. expectedBoolAssert: assert.True,
  993. },
  994. }
  995. for _, tc := range testCases {
  996. t.Run(tc.name, func(t *testing.T) {
  997. summaryDPS := pmetric.NewSummaryDataPointSlice()
  998. summaryDP := summaryDPS.AppendEmpty()
  999. summaryDP.SetSum(tc.summaryMetricValue.sum)
  1000. summaryDP.SetCount(tc.summaryMetricValue.count)
  1001. summaryDP.Attributes().PutStr("label1", "value1")
  1002. summaryDP.QuantileValues().EnsureCapacity(len(tc.summaryMetricValue.qMetrics))
  1003. for _, qMetric := range tc.summaryMetricValue.qMetrics {
  1004. newQ := summaryDP.QuantileValues().AppendEmpty()
  1005. newQ.SetValue(qMetric.value)
  1006. newQ.SetQuantile(qMetric.quantile)
  1007. }
  1008. summaryDatapointSlice := summaryDataPointSlice{deltaMetricMetadata{}, summaryDPS}
  1009. if tc.setFlagsFunc != nil {
  1010. tc.setFlagsFunc(summaryDatapointSlice.At(0))
  1011. }
  1012. isStaleOrNaN, _ := summaryDatapointSlice.IsStaleOrNaN(0)
  1013. tc.expectedBoolAssert(t, isStaleOrNaN)
  1014. })
  1015. }
  1016. }
  1017. func TestCreateLabels(t *testing.T) {
  1018. expectedLabels := map[string]string{
  1019. "a": "A",
  1020. "b": "B",
  1021. "c": "C",
  1022. }
  1023. labelsMap := pcommon.NewMap()
  1024. assert.NoError(t, labelsMap.FromRaw(map[string]any{
  1025. "a": "A",
  1026. "b": "B",
  1027. "c": "C",
  1028. }))
  1029. labels := createLabels(labelsMap, "")
  1030. assert.Equal(t, expectedLabels, labels)
  1031. // With isntrumentation library name
  1032. labels = createLabels(labelsMap, "cloudwatch-otel")
  1033. expectedLabels[oTellibDimensionKey] = "cloudwatch-otel"
  1034. assert.Equal(t, expectedLabels, labels)
  1035. }
  1036. func TestGetDataPoints(t *testing.T) {
  1037. logger := zap.NewNop()
  1038. normalDeltraMetricMetadata := generateDeltaMetricMetadata(false, "foo", false)
  1039. cumulativeDeltaMetricMetadata := generateDeltaMetricMetadata(true, "foo", false)
  1040. testCases := []struct {
  1041. name string
  1042. isPrometheusMetrics bool
  1043. metric pmetric.Metrics
  1044. expectedDatapointSlice dataPoints
  1045. expectedAttributes map[string]any
  1046. }{
  1047. {
  1048. name: "Int gauge",
  1049. isPrometheusMetrics: false,
  1050. metric: generateTestGaugeMetric("foo", intValueType),
  1051. expectedDatapointSlice: numberDataPointSlice{normalDeltraMetricMetadata, pmetric.NumberDataPointSlice{}},
  1052. expectedAttributes: map[string]any{"label1": "value1"},
  1053. },
  1054. {
  1055. name: "Double sum",
  1056. isPrometheusMetrics: false,
  1057. metric: generateTestSumMetric("foo", doubleValueType),
  1058. expectedDatapointSlice: numberDataPointSlice{cumulativeDeltaMetricMetadata, pmetric.NumberDataPointSlice{}},
  1059. expectedAttributes: map[string]any{"label1": "value1"},
  1060. },
  1061. {
  1062. name: "Histogram",
  1063. isPrometheusMetrics: false,
  1064. metric: generateTestHistogramMetric("foo"),
  1065. expectedDatapointSlice: histogramDataPointSlice{cumulativeDeltaMetricMetadata, pmetric.HistogramDataPointSlice{}},
  1066. expectedAttributes: map[string]any{"label1": "value1"},
  1067. },
  1068. {
  1069. name: "ExponentialHistogram",
  1070. isPrometheusMetrics: false,
  1071. metric: generateTestExponentialHistogramMetric("foo"),
  1072. expectedDatapointSlice: exponentialHistogramDataPointSlice{cumulativeDeltaMetricMetadata, pmetric.ExponentialHistogramDataPointSlice{}},
  1073. expectedAttributes: map[string]any{"label1": "value1"},
  1074. },
  1075. {
  1076. name: "Summary from SDK",
  1077. isPrometheusMetrics: false,
  1078. metric: generateTestSummaryMetric("foo"),
  1079. expectedDatapointSlice: summaryDataPointSlice{normalDeltraMetricMetadata, pmetric.SummaryDataPointSlice{}},
  1080. expectedAttributes: map[string]any{"label1": "value1"},
  1081. },
  1082. {
  1083. name: "Summary from Prometheus",
  1084. isPrometheusMetrics: true,
  1085. metric: generateTestSummaryMetric("foo"),
  1086. expectedDatapointSlice: summaryDataPointSlice{cumulativeDeltaMetricMetadata, pmetric.SummaryDataPointSlice{}},
  1087. expectedAttributes: map[string]any{"label1": "value1"},
  1088. },
  1089. }
  1090. for _, tc := range testCases {
  1091. rm := tc.metric.ResourceMetrics().At(0)
  1092. metrics := rm.ScopeMetrics().At(0).Metrics()
  1093. metric := metrics.At(metrics.Len() - 1)
  1094. metadata := generateTestMetricMetadata("namespace", time.Now().UnixNano()/int64(time.Millisecond), "log-group", "log-stream", "cloudwatch-otel", metric.Type())
  1095. t.Run(tc.name, func(t *testing.T) {
  1096. if tc.isPrometheusMetrics {
  1097. metadata.receiver = prometheusReceiver
  1098. } else {
  1099. metadata.receiver = ""
  1100. }
  1101. dps := getDataPoints(metric, metadata, logger)
  1102. assert.NotNil(t, dps)
  1103. assert.Equal(t, reflect.TypeOf(tc.expectedDatapointSlice), reflect.TypeOf(dps))
  1104. switch convertedDPS := dps.(type) {
  1105. case numberDataPointSlice:
  1106. expectedDPS := tc.expectedDatapointSlice.(numberDataPointSlice)
  1107. assert.Equal(t, expectedDPS.deltaMetricMetadata, convertedDPS.deltaMetricMetadata)
  1108. assert.Equal(t, 1, convertedDPS.Len())
  1109. dp := convertedDPS.NumberDataPointSlice.At(0)
  1110. switch dp.ValueType() {
  1111. case pmetric.NumberDataPointValueTypeDouble:
  1112. assert.Equal(t, 0.1, dp.DoubleValue())
  1113. case pmetric.NumberDataPointValueTypeInt:
  1114. assert.Equal(t, int64(1), dp.IntValue())
  1115. }
  1116. assert.Equal(t, tc.expectedAttributes, dp.Attributes().AsRaw())
  1117. case histogramDataPointSlice:
  1118. assert.Equal(t, 1, convertedDPS.Len())
  1119. dp := convertedDPS.HistogramDataPointSlice.At(0)
  1120. assert.Equal(t, 35.0, dp.Sum())
  1121. assert.Equal(t, uint64(18), dp.Count())
  1122. assert.Equal(t, []float64{0, 10}, dp.ExplicitBounds().AsRaw())
  1123. assert.Equal(t, tc.expectedAttributes, dp.Attributes().AsRaw())
  1124. case exponentialHistogramDataPointSlice:
  1125. assert.Equal(t, 1, convertedDPS.Len())
  1126. dp := convertedDPS.ExponentialHistogramDataPointSlice.At(0)
  1127. assert.Equal(t, float64(0), dp.Sum())
  1128. assert.Equal(t, uint64(4), dp.Count())
  1129. assert.Equal(t, []uint64{1, 0, 1}, dp.Positive().BucketCounts().AsRaw())
  1130. assert.Equal(t, []uint64{1, 0, 1}, dp.Negative().BucketCounts().AsRaw())
  1131. assert.Equal(t, uint64(0), dp.ZeroCount())
  1132. assert.Equal(t, tc.expectedAttributes, dp.Attributes().AsRaw())
  1133. case summaryDataPointSlice:
  1134. expectedDPS := tc.expectedDatapointSlice.(summaryDataPointSlice)
  1135. assert.Equal(t, expectedDPS.deltaMetricMetadata, convertedDPS.deltaMetricMetadata)
  1136. assert.Equal(t, 1, convertedDPS.Len())
  1137. dp := convertedDPS.SummaryDataPointSlice.At(0)
  1138. assert.Equal(t, 15.0, dp.Sum())
  1139. assert.Equal(t, uint64(5), dp.Count())
  1140. assert.Equal(t, 2, dp.QuantileValues().Len())
  1141. assert.Equal(t, float64(1), dp.QuantileValues().At(0).Value())
  1142. assert.Equal(t, float64(5), dp.QuantileValues().At(1).Value())
  1143. assert.Equal(t, tc.expectedAttributes, dp.Attributes().AsRaw())
  1144. }
  1145. })
  1146. }
  1147. t.Run("Unhandled metric type", func(t *testing.T) {
  1148. metric := pmetric.NewMetric()
  1149. metric.SetName("foo")
  1150. metric.SetUnit("Count")
  1151. metadata := generateTestMetricMetadata("namespace", time.Now().UnixNano()/int64(time.Millisecond), "log-group", "log-stream", "cloudwatch-otel", pmetric.MetricTypeEmpty)
  1152. obs, logs := observer.New(zap.WarnLevel)
  1153. logger := zap.New(obs)
  1154. dps := getDataPoints(metric, metadata, logger)
  1155. assert.Nil(t, dps)
  1156. // Test output warning logs
  1157. expectedLogs := []observer.LoggedEntry{
  1158. {
  1159. Entry: zapcore.Entry{Level: zap.WarnLevel, Message: "Unhandled metric data type."},
  1160. Context: []zapcore.Field{
  1161. zap.String("DataType", "Empty"),
  1162. zap.String("Name", "foo"),
  1163. zap.String("Unit", "Count"),
  1164. },
  1165. },
  1166. }
  1167. assert.Equal(t, 1, logs.Len())
  1168. assert.Equal(t, expectedLogs, logs.AllUntimed())
  1169. })
  1170. }
  1171. func BenchmarkGetAndCalculateDeltaDataPoints(b *testing.B) {
  1172. generateMetrics := []pmetric.Metrics{
  1173. generateTestGaugeMetric("int-gauge", intValueType),
  1174. generateTestGaugeMetric("int-gauge", doubleValueType),
  1175. generateTestHistogramMetric("histogram"),
  1176. generateTestExponentialHistogramMetric("exponential-histogram"),
  1177. generateTestSumMetric("int-sum", intValueType),
  1178. generateTestSumMetric("double-sum", doubleValueType),
  1179. generateTestSummaryMetric("summary"),
  1180. }
  1181. finalOtelMetrics := generateOtelTestMetrics(generateMetrics...)
  1182. rms := finalOtelMetrics.ResourceMetrics()
  1183. metrics := rms.At(0).ScopeMetrics().At(0).Metrics()
  1184. emfCalcs := setupEmfCalculators()
  1185. defer require.NoError(b, shutdownEmfCalculators(emfCalcs))
  1186. b.ResetTimer()
  1187. for n := 0; n < b.N; n++ {
  1188. for i := 0; i < metrics.Len(); i++ {
  1189. metadata := generateTestMetricMetadata("namespace", time.Now().UnixNano()/int64(time.Millisecond), "log-group", "log-stream", "cloudwatch-otel", metrics.At(i).Type())
  1190. dps := getDataPoints(metrics.At(i), metadata, zap.NewNop())
  1191. for i := 0; i < dps.Len(); i++ {
  1192. dps.CalculateDeltaDatapoints(i, "", false, emfCalcs)
  1193. }
  1194. }
  1195. }
  1196. }