metrics_adjuster_test.go 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. package internal
  4. import (
  5. "testing"
  6. "time"
  7. "github.com/stretchr/testify/assert"
  8. "go.opentelemetry.io/collector/pdata/pcommon"
  9. "go.opentelemetry.io/collector/pdata/pmetric"
  10. semconv "go.opentelemetry.io/collector/semconv/v1.8.0"
  11. "go.uber.org/zap"
  12. )
  13. var (
  14. tUnknown = timestampFromMs(0)
  15. t1 = timestampFromMs(1)
  16. t2 = timestampFromMs(2)
  17. t3 = timestampFromMs(3)
  18. t4 = timestampFromMs(4)
  19. t5 = timestampFromMs(5)
  20. bounds0 = []float64{1, 2, 4}
  21. percent0 = []float64{10, 50, 90}
  22. sum1 = "sum1"
  23. gauge1 = "gauge1"
  24. histogram1 = "histogram1"
  25. summary1 = "summary1"
  26. k1v1k2v2 = []*kv{
  27. {"k1", "v1"},
  28. {"k2", "v2"},
  29. }
  30. k1v10k2v20 = []*kv{
  31. {"k1", "v10"},
  32. {"k2", "v20"},
  33. }
  34. k1v100k2v200 = []*kv{
  35. {"k1", "v100"},
  36. {"k2", "v200"},
  37. }
  38. emptyLabels []*kv
  39. k1vEmpty = []*kv{{"k1", ""}}
  40. k1vEmptyk2vEmptyk3vEmpty = []*kv{{"k1", ""}, {"k2", ""}, {"k3", ""}}
  41. )
  42. func TestGauge(t *testing.T) {
  43. script := []*metricsAdjusterTest{
  44. {
  45. description: "Gauge: round 1 - gauge not adjusted",
  46. metrics: metrics(gaugeMetric(gauge1, doublePoint(k1v1k2v2, t1, t1, 44))),
  47. adjusted: metrics(gaugeMetric(gauge1, doublePoint(k1v1k2v2, t1, t1, 44))),
  48. },
  49. {
  50. description: "Gauge: round 2 - gauge not adjusted",
  51. metrics: metrics(gaugeMetric(gauge1, doublePoint(k1v1k2v2, t2, t2, 66))),
  52. adjusted: metrics(gaugeMetric(gauge1, doublePoint(k1v1k2v2, t2, t2, 66))),
  53. },
  54. {
  55. description: "Gauge: round 3 - value less than previous value - gauge is not adjusted",
  56. metrics: metrics(gaugeMetric(gauge1, doublePoint(k1v1k2v2, t3, t3, 55))),
  57. adjusted: metrics(gaugeMetric(gauge1, doublePoint(k1v1k2v2, t3, t3, 55))),
  58. },
  59. }
  60. runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute, true), "job", "0", script)
  61. }
  62. func TestSum(t *testing.T) {
  63. script := []*metricsAdjusterTest{
  64. {
  65. description: "Sum: round 1 - initial instance, start time is established",
  66. metrics: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44))),
  67. adjusted: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44))),
  68. },
  69. {
  70. description: "Sum: round 2 - instance adjusted based on round 1",
  71. metrics: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t2, t2, 66))),
  72. adjusted: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t1, t2, 66))),
  73. },
  74. {
  75. description: "Sum: round 3 - instance reset (value less than previous value), start time is reset",
  76. metrics: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t3, t3, 55))),
  77. adjusted: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t3, t3, 55))),
  78. },
  79. {
  80. description: "Sum: round 4 - instance adjusted based on round 3",
  81. metrics: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t4, t4, 72))),
  82. adjusted: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t3, t4, 72))),
  83. },
  84. {
  85. description: "Sum: round 5 - instance adjusted based on round 4",
  86. metrics: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t5, t5, 72))),
  87. adjusted: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t3, t5, 72))),
  88. },
  89. }
  90. runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute, true), "job", "0", script)
  91. }
  92. func TestSummaryNoCount(t *testing.T) {
  93. script := []*metricsAdjusterTest{
  94. {
  95. description: "Summary No Count: round 1 - initial instance, start time is established",
  96. metrics: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 0, 40, percent0, []float64{1, 5, 8}))),
  97. adjusted: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 0, 40, percent0, []float64{1, 5, 8}))),
  98. },
  99. {
  100. description: "Summary No Count: round 2 - instance adjusted based on round 1",
  101. metrics: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t2, t2, 0, 70, percent0, []float64{7, 44, 9}))),
  102. adjusted: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t2, 0, 70, percent0, []float64{7, 44, 9}))),
  103. },
  104. {
  105. description: "Summary No Count: round 3 - instance reset (count less than previous), start time is reset",
  106. metrics: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t3, 0, 66, percent0, []float64{3, 22, 5}))),
  107. adjusted: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t3, 0, 66, percent0, []float64{3, 22, 5}))),
  108. },
  109. {
  110. description: "Summary No Count: round 4 - instance adjusted based on round 3",
  111. metrics: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t4, t4, 0, 96, percent0, []float64{9, 47, 8}))),
  112. adjusted: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t4, 0, 96, percent0, []float64{9, 47, 8}))),
  113. },
  114. }
  115. runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute, true), "job", "0", script)
  116. }
  117. func TestSummaryFlagNoRecordedValue(t *testing.T) {
  118. script := []*metricsAdjusterTest{
  119. {
  120. description: "Summary No Count: round 1 - initial instance, start time is established",
  121. metrics: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 0, 40, percent0, []float64{1, 5, 8}))),
  122. adjusted: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 0, 40, percent0, []float64{1, 5, 8}))),
  123. },
  124. {
  125. description: "Summary Flag NoRecordedValue: round 2 - instance adjusted based on round 1",
  126. metrics: metrics(summaryMetric(summary1, summaryPointNoValue(k1v1k2v2, t2, t2))),
  127. adjusted: metrics(summaryMetric(summary1, summaryPointNoValue(k1v1k2v2, t1, t2))),
  128. },
  129. }
  130. runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute, true), "job", "0", script)
  131. }
  132. func TestSummary(t *testing.T) {
  133. script := []*metricsAdjusterTest{
  134. {
  135. description: "Summary: round 1 - initial instance, start time is established",
  136. metrics: metrics(
  137. summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 10, 40, percent0, []float64{1, 5, 8})),
  138. ),
  139. adjusted: metrics(
  140. summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 10, 40, percent0, []float64{1, 5, 8})),
  141. ),
  142. },
  143. {
  144. description: "Summary: round 2 - instance adjusted based on round 1",
  145. metrics: metrics(
  146. summaryMetric(summary1, summaryPoint(k1v1k2v2, t2, t2, 15, 70, percent0, []float64{7, 44, 9})),
  147. ),
  148. adjusted: metrics(
  149. summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t2, 15, 70, percent0, []float64{7, 44, 9})),
  150. ),
  151. },
  152. {
  153. description: "Summary: round 3 - instance reset (count less than previous), start time is reset",
  154. metrics: metrics(
  155. summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t3, 12, 66, percent0, []float64{3, 22, 5})),
  156. ),
  157. adjusted: metrics(
  158. summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t3, 12, 66, percent0, []float64{3, 22, 5})),
  159. ),
  160. },
  161. {
  162. description: "Summary: round 4 - instance adjusted based on round 3",
  163. metrics: metrics(
  164. summaryMetric(summary1, summaryPoint(k1v1k2v2, t4, t4, 14, 96, percent0, []float64{9, 47, 8})),
  165. ),
  166. adjusted: metrics(
  167. summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t4, 14, 96, percent0, []float64{9, 47, 8})),
  168. ),
  169. },
  170. }
  171. runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute, true), "job", "0", script)
  172. }
  173. func TestHistogram(t *testing.T) {
  174. script := []*metricsAdjusterTest{
  175. {
  176. description: "Histogram: round 1 - initial instance, start time is established",
  177. metrics: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7}))),
  178. adjusted: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7}))),
  179. }, {
  180. description: "Histogram: round 2 - instance adjusted based on round 1",
  181. metrics: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t2, t2, bounds0, []uint64{6, 3, 4, 8}))),
  182. adjusted: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t2, bounds0, []uint64{6, 3, 4, 8}))),
  183. }, {
  184. description: "Histogram: round 3 - instance reset (value less than previous value), start time is reset",
  185. metrics: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t3, t3, bounds0, []uint64{5, 3, 2, 7}))),
  186. adjusted: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t3, t3, bounds0, []uint64{5, 3, 2, 7}))),
  187. }, {
  188. description: "Histogram: round 4 - instance adjusted based on round 3",
  189. metrics: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t4, t4, bounds0, []uint64{7, 4, 2, 12}))),
  190. adjusted: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t3, t4, bounds0, []uint64{7, 4, 2, 12}))),
  191. },
  192. }
  193. runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute, true), "job", "0", script)
  194. }
  195. func TestHistogramFlagNoRecordedValue(t *testing.T) {
  196. script := []*metricsAdjusterTest{
  197. {
  198. description: "Histogram: round 1 - initial instance, start time is established",
  199. metrics: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{7, 4, 2, 12}))),
  200. adjusted: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{7, 4, 2, 12}))),
  201. },
  202. {
  203. description: "Histogram: round 2 - instance adjusted based on round 1",
  204. metrics: metrics(histogramMetric(histogram1, histogramPointNoValue(k1v1k2v2, tUnknown, t2))),
  205. adjusted: metrics(histogramMetric(histogram1, histogramPointNoValue(k1v1k2v2, t1, t2))),
  206. },
  207. }
  208. runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute, true), "job", "0", script)
  209. }
  210. func TestHistogramFlagNoRecordedValueFirstObservation(t *testing.T) {
  211. script := []*metricsAdjusterTest{
  212. {
  213. description: "Histogram: round 1 - initial instance, start time is unknown",
  214. metrics: metrics(histogramMetric(histogram1, histogramPointNoValue(k1v1k2v2, tUnknown, t1))),
  215. adjusted: metrics(histogramMetric(histogram1, histogramPointNoValue(k1v1k2v2, tUnknown, t1))),
  216. },
  217. {
  218. description: "Histogram: round 2 - instance unchanged",
  219. metrics: metrics(histogramMetric(histogram1, histogramPointNoValue(k1v1k2v2, tUnknown, t2))),
  220. adjusted: metrics(histogramMetric(histogram1, histogramPointNoValue(k1v1k2v2, tUnknown, t2))),
  221. },
  222. }
  223. runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute, true), "job", "0", script)
  224. }
  225. func TestSummaryFlagNoRecordedValueFirstObservation(t *testing.T) {
  226. script := []*metricsAdjusterTest{
  227. {
  228. description: "Summary: round 1 - initial instance, start time is unknown",
  229. metrics: metrics(summaryMetric(summary1, summaryPointNoValue(k1v1k2v2, tUnknown, t1))),
  230. adjusted: metrics(summaryMetric(summary1, summaryPointNoValue(k1v1k2v2, tUnknown, t1))),
  231. },
  232. {
  233. description: "Summary: round 2 - instance unchanged",
  234. metrics: metrics(summaryMetric(summary1, summaryPointNoValue(k1v1k2v2, tUnknown, t2))),
  235. adjusted: metrics(summaryMetric(summary1, summaryPointNoValue(k1v1k2v2, tUnknown, t2))),
  236. },
  237. }
  238. runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute, true), "job", "0", script)
  239. }
  240. func TestGaugeFlagNoRecordedValueFirstObservation(t *testing.T) {
  241. script := []*metricsAdjusterTest{
  242. {
  243. description: "Gauge: round 1 - initial instance, start time is unknown",
  244. metrics: metrics(gaugeMetric(gauge1, doublePointNoValue(k1v1k2v2, tUnknown, t1))),
  245. adjusted: metrics(gaugeMetric(gauge1, doublePointNoValue(k1v1k2v2, tUnknown, t1))),
  246. },
  247. {
  248. description: "Gauge: round 2 - instance unchanged",
  249. metrics: metrics(gaugeMetric(gauge1, doublePointNoValue(k1v1k2v2, tUnknown, t2))),
  250. adjusted: metrics(gaugeMetric(gauge1, doublePointNoValue(k1v1k2v2, tUnknown, t2))),
  251. },
  252. }
  253. runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute, true), "job", "0", script)
  254. }
  255. func TestSumFlagNoRecordedValueFirstObservation(t *testing.T) {
  256. script := []*metricsAdjusterTest{
  257. {
  258. description: "Sum: round 1 - initial instance, start time is unknown",
  259. metrics: metrics(sumMetric("sum1", doublePointNoValue(k1v1k2v2, tUnknown, t1))),
  260. adjusted: metrics(sumMetric("sum1", doublePointNoValue(k1v1k2v2, tUnknown, t1))),
  261. },
  262. {
  263. description: "Sum: round 2 - instance unchanged",
  264. metrics: metrics(sumMetric("sum1", doublePointNoValue(k1v1k2v2, tUnknown, t2))),
  265. adjusted: metrics(sumMetric("sum1", doublePointNoValue(k1v1k2v2, tUnknown, t2))),
  266. },
  267. }
  268. runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute, true), "job", "0", script)
  269. }
  270. func TestMultiMetrics(t *testing.T) {
  271. script := []*metricsAdjusterTest{
  272. {
  273. description: "MultiMetrics: round 1 - combined round 1 of individual metrics",
  274. metrics: metrics(
  275. gaugeMetric(gauge1, doublePoint(k1v1k2v2, t1, t1, 44)),
  276. sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44)),
  277. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7})),
  278. summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 10, 40, percent0, []float64{1, 5, 8})),
  279. ),
  280. adjusted: metrics(
  281. gaugeMetric(gauge1, doublePoint(k1v1k2v2, t1, t1, 44)),
  282. sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44)),
  283. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7})),
  284. summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 10, 40, percent0, []float64{1, 5, 8})),
  285. ),
  286. },
  287. {
  288. description: "MultiMetrics: round 2 - combined round 2 of individual metrics",
  289. metrics: metrics(
  290. gaugeMetric(gauge1, doublePoint(k1v1k2v2, t2, t2, 66)),
  291. sumMetric(sum1, doublePoint(k1v1k2v2, t2, t2, 66)),
  292. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t2, t2, bounds0, []uint64{6, 3, 4, 8})),
  293. summaryMetric(summary1, summaryPoint(k1v1k2v2, t2, t2, 15, 70, percent0, []float64{7, 44, 9})),
  294. ),
  295. adjusted: metrics(
  296. gaugeMetric(gauge1, doublePoint(k1v1k2v2, t2, t2, 66)),
  297. sumMetric(sum1, doublePoint(k1v1k2v2, t1, t2, 66)),
  298. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t2, bounds0, []uint64{6, 3, 4, 8})),
  299. summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t2, 15, 70, percent0, []float64{7, 44, 9})),
  300. ),
  301. },
  302. {
  303. description: "MultiMetrics: round 3 - combined round 3 of individual metrics",
  304. metrics: metrics(
  305. gaugeMetric(gauge1, doublePoint(k1v1k2v2, t3, t3, 55)),
  306. sumMetric(sum1, doublePoint(k1v1k2v2, t3, t3, 55)),
  307. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t3, t3, bounds0, []uint64{5, 3, 2, 7})),
  308. summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t3, 12, 66, percent0, []float64{3, 22, 5})),
  309. ),
  310. adjusted: metrics(
  311. gaugeMetric(gauge1, doublePoint(k1v1k2v2, t3, t3, 55)),
  312. sumMetric(sum1, doublePoint(k1v1k2v2, t3, t3, 55)),
  313. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t3, t3, bounds0, []uint64{5, 3, 2, 7})),
  314. summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t3, 12, 66, percent0, []float64{3, 22, 5})),
  315. ),
  316. },
  317. {
  318. description: "MultiMetrics: round 4 - combined round 4 of individual metrics",
  319. metrics: metrics(
  320. sumMetric(sum1, doublePoint(k1v1k2v2, t4, t4, 72)),
  321. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t4, t4, bounds0, []uint64{7, 4, 2, 12})),
  322. summaryMetric(summary1, summaryPoint(k1v1k2v2, t4, t4, 14, 96, percent0, []float64{9, 47, 8})),
  323. ),
  324. adjusted: metrics(
  325. sumMetric(sum1, doublePoint(k1v1k2v2, t3, t4, 72)),
  326. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t3, t4, bounds0, []uint64{7, 4, 2, 12})),
  327. summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t4, 14, 96, percent0, []float64{9, 47, 8})),
  328. ),
  329. },
  330. }
  331. runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute, true), "job", "0", script)
  332. }
  333. func TestNewDataPointsAdded(t *testing.T) {
  334. script := []*metricsAdjusterTest{
  335. {
  336. description: "New Datapoints: round 1 - two datapoints each",
  337. metrics: metrics(
  338. sumMetric(sum1,
  339. doublePoint(k1v1k2v2, t1, t1, 44),
  340. doublePoint(k1v100k2v200, t1, t1, 44)),
  341. histogramMetric(histogram1,
  342. histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7}),
  343. histogramPoint(k1v100k2v200, t1, t1, bounds0, []uint64{4, 2, 3, 7})),
  344. summaryMetric(summary1,
  345. summaryPoint(k1v1k2v2, t1, t1, 10, 40, percent0, []float64{1, 5, 8}),
  346. summaryPoint(k1v100k2v200, t1, t1, 10, 40, percent0, []float64{1, 5, 8})),
  347. ),
  348. adjusted: metrics(
  349. sumMetric(sum1,
  350. doublePoint(k1v1k2v2, t1, t1, 44),
  351. doublePoint(k1v100k2v200, t1, t1, 44)),
  352. histogramMetric(histogram1,
  353. histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7}),
  354. histogramPoint(k1v100k2v200, t1, t1, bounds0, []uint64{4, 2, 3, 7})),
  355. summaryMetric(summary1,
  356. summaryPoint(k1v1k2v2, t1, t1, 10, 40, percent0, []float64{1, 5, 8}),
  357. summaryPoint(k1v100k2v200, t1, t1, 10, 40, percent0, []float64{1, 5, 8})),
  358. ),
  359. },
  360. {
  361. description: "New Datapoints: round 2 - new datapoints unchanged, old datapoints adjusted",
  362. metrics: metrics(
  363. sumMetric(sum1,
  364. doublePoint(k1v1k2v2, t2, t2, 44),
  365. doublePoint(k1v10k2v20, t2, t2, 44),
  366. doublePoint(k1v100k2v200, t2, t2, 44)),
  367. histogramMetric(histogram1,
  368. histogramPoint(k1v1k2v2, t2, t2, bounds0, []uint64{4, 2, 3, 7}),
  369. histogramPoint(k1v10k2v20, t2, t2, bounds0, []uint64{4, 2, 3, 7}),
  370. histogramPoint(k1v100k2v200, t2, t2, bounds0, []uint64{4, 2, 3, 7})),
  371. summaryMetric(summary1,
  372. summaryPoint(k1v1k2v2, t2, t2, 10, 40, percent0, []float64{1, 5, 8}),
  373. summaryPoint(k1v10k2v20, t2, t2, 10, 40, percent0, []float64{1, 5, 8}),
  374. summaryPoint(k1v100k2v200, t2, t2, 10, 40, percent0, []float64{1, 5, 8})),
  375. ),
  376. adjusted: metrics(
  377. sumMetric(sum1,
  378. doublePoint(k1v1k2v2, t1, t2, 44),
  379. doublePoint(k1v10k2v20, t2, t2, 44),
  380. doublePoint(k1v100k2v200, t1, t2, 44)),
  381. histogramMetric(histogram1,
  382. histogramPoint(k1v1k2v2, t1, t2, bounds0, []uint64{4, 2, 3, 7}),
  383. histogramPoint(k1v10k2v20, t2, t2, bounds0, []uint64{4, 2, 3, 7}),
  384. histogramPoint(k1v100k2v200, t1, t2, bounds0, []uint64{4, 2, 3, 7})),
  385. summaryMetric(summary1,
  386. summaryPoint(k1v1k2v2, t1, t2, 10, 40, percent0, []float64{1, 5, 8}),
  387. summaryPoint(k1v10k2v20, t2, t2, 10, 40, percent0, []float64{1, 5, 8}),
  388. summaryPoint(k1v100k2v200, t1, t2, 10, 40, percent0, []float64{1, 5, 8})),
  389. ),
  390. },
  391. }
  392. runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute, true), "job", "0", script)
  393. }
  394. func TestMultiTimeseries(t *testing.T) {
  395. script := []*metricsAdjusterTest{
  396. {
  397. description: "MultiTimeseries: round 1 - initial first instance, start time is established",
  398. metrics: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44))),
  399. adjusted: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44))),
  400. },
  401. {
  402. description: "MultiTimeseries: round 2 - first instance adjusted based on round 1, initial second instance",
  403. metrics: metrics(
  404. sumMetric(sum1, doublePoint(k1v1k2v2, t2, t2, 66)),
  405. sumMetric(sum1, doublePoint(k1v10k2v20, t2, t2, 20.0)),
  406. ),
  407. adjusted: metrics(
  408. sumMetric(sum1, doublePoint(k1v1k2v2, t1, t2, 66)),
  409. sumMetric(sum1, doublePoint(k1v10k2v20, t2, t2, 20.0)),
  410. ),
  411. },
  412. {
  413. description: "MultiTimeseries: round 3 - first instance adjusted based on round 1, second based on round 2",
  414. metrics: metrics(
  415. sumMetric(sum1, doublePoint(k1v1k2v2, t3, t3, 88.0)),
  416. sumMetric(sum1, doublePoint(k1v10k2v20, t3, t3, 49.0)),
  417. ),
  418. adjusted: metrics(
  419. sumMetric(sum1, doublePoint(k1v1k2v2, t1, t3, 88.0)),
  420. sumMetric(sum1, doublePoint(k1v10k2v20, t2, t3, 49.0)),
  421. ),
  422. },
  423. {
  424. description: "MultiTimeseries: round 4 - first instance reset, second instance adjusted based on round 2, initial third instance",
  425. metrics: metrics(
  426. sumMetric(sum1, doublePoint(k1v1k2v2, t4, t4, 87.0)),
  427. sumMetric(sum1, doublePoint(k1v10k2v20, t4, t4, 57.0)),
  428. sumMetric(sum1, doublePoint(k1v100k2v200, t4, t4, 10.0)),
  429. ),
  430. adjusted: metrics(
  431. sumMetric(sum1, doublePoint(k1v1k2v2, t4, t4, 87.0)),
  432. sumMetric(sum1, doublePoint(k1v10k2v20, t2, t4, 57.0)),
  433. sumMetric(sum1, doublePoint(k1v100k2v200, t4, t4, 10.0)),
  434. ),
  435. },
  436. {
  437. description: "MultiTimeseries: round 5 - first instance adjusted based on round 4, second on round 2, third on round 4",
  438. metrics: metrics(
  439. sumMetric(sum1, doublePoint(k1v1k2v2, t5, t5, 90.0)),
  440. sumMetric(sum1, doublePoint(k1v10k2v20, t5, t5, 65.0)),
  441. sumMetric(sum1, doublePoint(k1v100k2v200, t5, t5, 22.0)),
  442. ),
  443. adjusted: metrics(
  444. sumMetric(sum1, doublePoint(k1v1k2v2, t4, t5, 90.0)),
  445. sumMetric(sum1, doublePoint(k1v10k2v20, t2, t5, 65.0)),
  446. sumMetric(sum1, doublePoint(k1v100k2v200, t4, t5, 22.0)),
  447. ),
  448. },
  449. }
  450. runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute, true), "job", "0", script)
  451. }
  452. func TestEmptyLabels(t *testing.T) {
  453. script := []*metricsAdjusterTest{
  454. {
  455. description: "EmptyLabels: round 1 - initial instance, implicitly empty labels, start time is established",
  456. metrics: metrics(sumMetric(sum1, doublePoint(emptyLabels, t1, t1, 44))),
  457. adjusted: metrics(sumMetric(sum1, doublePoint(emptyLabels, t1, t1, 44))),
  458. },
  459. {
  460. description: "EmptyLabels: round 2 - instance adjusted based on round 1",
  461. metrics: metrics(sumMetric(sum1, doublePoint(emptyLabels, t2, t2, 66))),
  462. adjusted: metrics(sumMetric(sum1, doublePoint(emptyLabels, t1, t2, 66))),
  463. },
  464. {
  465. description: "EmptyLabels: round 3 - one explicitly empty label, instance adjusted based on round 1",
  466. metrics: metrics(sumMetric(sum1, doublePoint(k1vEmpty, t3, t3, 77))),
  467. adjusted: metrics(sumMetric(sum1, doublePoint(k1vEmpty, t1, t3, 77))),
  468. },
  469. {
  470. description: "EmptyLabels: round 4 - three explicitly empty labels, instance adjusted based on round 1",
  471. metrics: metrics(sumMetric(sum1, doublePoint(k1vEmptyk2vEmptyk3vEmpty, t3, t3, 88))),
  472. adjusted: metrics(sumMetric(sum1, doublePoint(k1vEmptyk2vEmptyk3vEmpty, t1, t3, 88))),
  473. },
  474. }
  475. runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute, true), "job", "0", script)
  476. }
  477. func TestTsGC(t *testing.T) {
  478. script1 := []*metricsAdjusterTest{
  479. {
  480. description: "TsGC: round 1 - initial instances, start time is established",
  481. metrics: metrics(
  482. sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44)),
  483. sumMetric(sum1, doublePoint(k1v10k2v20, t1, t1, 20)),
  484. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7})),
  485. histogramMetric(histogram1, histogramPoint(k1v10k2v20, t1, t1, bounds0, []uint64{40, 20, 30, 70})),
  486. ),
  487. adjusted: metrics(
  488. sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44)),
  489. sumMetric(sum1, doublePoint(k1v10k2v20, t1, t1, 20)),
  490. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7})),
  491. histogramMetric(histogram1, histogramPoint(k1v10k2v20, t1, t1, bounds0, []uint64{40, 20, 30, 70})),
  492. ),
  493. },
  494. }
  495. script2 := []*metricsAdjusterTest{
  496. {
  497. description: "TsGC: round 2 - metrics first timeseries adjusted based on round 2, second timeseries not updated",
  498. metrics: metrics(
  499. sumMetric(sum1, doublePoint(k1v1k2v2, t2, t2, 88)),
  500. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t2, t2, bounds0, []uint64{8, 7, 9, 14})),
  501. ),
  502. adjusted: metrics(
  503. sumMetric(sum1, doublePoint(k1v1k2v2, t1, t2, 88)),
  504. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t2, bounds0, []uint64{8, 7, 9, 14})),
  505. ),
  506. },
  507. }
  508. script3 := []*metricsAdjusterTest{
  509. {
  510. description: "TsGC: round 3 - metrics first timeseries adjusted based on round 2, second timeseries empty due to timeseries gc()",
  511. metrics: metrics(
  512. sumMetric(sum1, doublePoint(k1v1k2v2, t3, t3, 99)),
  513. sumMetric(sum1, doublePoint(k1v10k2v20, t3, t3, 80)),
  514. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t3, t3, bounds0, []uint64{9, 8, 10, 15})),
  515. histogramMetric(histogram1, histogramPoint(k1v10k2v20, t3, t3, bounds0, []uint64{55, 66, 33, 77})),
  516. ),
  517. adjusted: metrics(
  518. sumMetric(sum1, doublePoint(k1v1k2v2, t1, t3, 99)),
  519. sumMetric(sum1, doublePoint(k1v10k2v20, t3, t3, 80)),
  520. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t3, bounds0, []uint64{9, 8, 10, 15})),
  521. histogramMetric(histogram1, histogramPoint(k1v10k2v20, t3, t3, bounds0, []uint64{55, 66, 33, 77})),
  522. ),
  523. },
  524. }
  525. ma := NewInitialPointAdjuster(zap.NewNop(), time.Minute, true)
  526. // run round 1
  527. runScript(t, ma, "job", "0", script1)
  528. // gc the tsmap, unmarking all entries
  529. ma.(*initialPointAdjuster).jobsMap.get("job", "0").gc()
  530. // run round 2 - update metrics first timeseries only
  531. runScript(t, ma, "job", "0", script2)
  532. // gc the tsmap, collecting umarked entries
  533. ma.(*initialPointAdjuster).jobsMap.get("job", "0").gc()
  534. // run round 3 - verify that metrics second timeseries have been gc'd
  535. runScript(t, ma, "job", "0", script3)
  536. }
  537. func TestJobGC(t *testing.T) {
  538. job1Script1 := []*metricsAdjusterTest{
  539. {
  540. description: "JobGC: job 1, round 1 - initial instances, adjusted should be empty",
  541. metrics: metrics(
  542. sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44)),
  543. sumMetric(sum1, doublePoint(k1v10k2v20, t1, t1, 20)),
  544. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7})),
  545. histogramMetric(histogram1, histogramPoint(k1v10k2v20, t1, t1, bounds0, []uint64{40, 20, 30, 70})),
  546. ),
  547. adjusted: metrics(
  548. sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44)),
  549. sumMetric(sum1, doublePoint(k1v10k2v20, t1, t1, 20)),
  550. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7})),
  551. histogramMetric(histogram1, histogramPoint(k1v10k2v20, t1, t1, bounds0, []uint64{40, 20, 30, 70})),
  552. ),
  553. },
  554. }
  555. job2Script1 := []*metricsAdjusterTest{
  556. {
  557. description: "JobGC: job2, round 1 - no metrics adjusted, just trigger gc",
  558. metrics: metrics(),
  559. adjusted: metrics(),
  560. },
  561. }
  562. job1Script2 := []*metricsAdjusterTest{
  563. {
  564. description: "JobGC: job 1, round 2 - metrics timeseries empty due to job-level gc",
  565. metrics: metrics(
  566. sumMetric(sum1, doublePoint(k1v1k2v2, t4, t4, 99)),
  567. sumMetric(sum1, doublePoint(k1v10k2v20, t4, t4, 80)),
  568. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t4, t4, bounds0, []uint64{9, 8, 10, 15})),
  569. histogramMetric(histogram1, histogramPoint(k1v10k2v20, t4, t4, bounds0, []uint64{55, 66, 33, 77})),
  570. ),
  571. adjusted: metrics(
  572. sumMetric(sum1, doublePoint(k1v1k2v2, t4, t4, 99)),
  573. sumMetric(sum1, doublePoint(k1v10k2v20, t4, t4, 80)),
  574. histogramMetric(histogram1, histogramPoint(k1v1k2v2, t4, t4, bounds0, []uint64{9, 8, 10, 15})),
  575. histogramMetric(histogram1, histogramPoint(k1v10k2v20, t4, t4, bounds0, []uint64{55, 66, 33, 77})),
  576. ),
  577. },
  578. }
  579. gcInterval := 10 * time.Millisecond
  580. ma := NewInitialPointAdjuster(zap.NewNop(), gcInterval, true)
  581. // run job 1, round 1 - all entries marked
  582. runScript(t, ma, "job1", "0", job1Script1)
  583. // sleep longer than gcInterval to enable job gc in the next run
  584. time.Sleep(2 * gcInterval)
  585. // run job 2, round1 - trigger job gc, unmarking all entries
  586. runScript(t, ma, "job1", "1", job2Script1)
  587. // sleep longer than gcInterval to enable job gc in the next run
  588. time.Sleep(2 * gcInterval)
  589. // re-run job 2, round1 - trigger job gc, removing unmarked entries
  590. runScript(t, ma, "job1", "1", job2Script1)
  591. // ensure that at least one jobsMap.gc() completed
  592. ma.(*initialPointAdjuster).jobsMap.gc()
  593. // run job 1, round 2 - verify that all job 1 timeseries have been gc'd
  594. runScript(t, ma, "job1", "0", job1Script2)
  595. }
  596. type metricsAdjusterTest struct {
  597. description string
  598. metrics pmetric.Metrics
  599. adjusted pmetric.Metrics
  600. }
  601. func runScript(t *testing.T, ma MetricsAdjuster, job, instance string, tests []*metricsAdjusterTest) {
  602. for _, test := range tests {
  603. t.Run(test.description, func(t *testing.T) {
  604. adjusted := pmetric.NewMetrics()
  605. test.metrics.CopyTo(adjusted)
  606. // Add the instance/job to the input metrics.
  607. adjusted.ResourceMetrics().At(0).Resource().Attributes().PutStr(semconv.AttributeServiceInstanceID, instance)
  608. adjusted.ResourceMetrics().At(0).Resource().Attributes().PutStr(semconv.AttributeServiceName, job)
  609. assert.NoError(t, ma.AdjustMetrics(adjusted))
  610. // Add the instance/job to the expected metrics as well.
  611. test.adjusted.ResourceMetrics().At(0).Resource().Attributes().PutStr(semconv.AttributeServiceInstanceID, instance)
  612. test.adjusted.ResourceMetrics().At(0).Resource().Attributes().PutStr(semconv.AttributeServiceName, job)
  613. assert.EqualValues(t, test.adjusted, adjusted)
  614. })
  615. }
  616. }
  617. func BenchmarkGetAttributesSignature(b *testing.B) {
  618. attrs := pcommon.NewMap()
  619. attrs.PutStr("key1", "some-random-test-value-1")
  620. attrs.PutStr("key2", "some-random-test-value-2")
  621. attrs.PutStr("key6", "some-random-test-value-6")
  622. attrs.PutStr("key3", "some-random-test-value-3")
  623. attrs.PutStr("key4", "some-random-test-value-4")
  624. attrs.PutStr("key5", "some-random-test-value-5")
  625. attrs.PutStr("key7", "some-random-test-value-7")
  626. attrs.PutStr("key8", "some-random-test-value-8")
  627. b.ResetTimer()
  628. b.ReportAllocs()
  629. for i := 0; i < b.N; i++ {
  630. getAttributesSignature(attrs)
  631. }
  632. }