1use std::collections::BTreeMap;
2
3use mlua::prelude::*;
4
5use super::{
6 super::{
7 Metric, MetricKind, MetricValue, StatisticKind,
8 metric::{self, MetricSketch, MetricTags, TagValue, TagValueSet},
9 },
10 util::{table_to_timestamp, timestamp_to_table},
11};
12use crate::metrics::AgentDDSketch;
13
14pub struct LuaMetric {
15 pub metric: Metric,
16 pub multi_value_tags: bool,
17}
18
19pub struct LuaMetricTags {
20 pub tags: MetricTags,
21 pub multi_value_tags: bool,
22}
23
24impl IntoLua for MetricKind {
25 #![allow(clippy::wrong_self_convention)] fn into_lua(self, lua: &Lua) -> LuaResult<LuaValue> {
27 let kind = match self {
28 MetricKind::Absolute => "absolute",
29 MetricKind::Incremental => "incremental",
30 };
31 lua.create_string(kind).map(LuaValue::String)
32 }
33}
34
35impl FromLua for MetricKind {
36 fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
37 match value {
38 LuaValue::String(s) if s == "absolute" => Ok(MetricKind::Absolute),
39 LuaValue::String(s) if s == "incremental" => Ok(MetricKind::Incremental),
40 _ => Err(LuaError::FromLuaConversionError {
41 from: value.type_name(),
42 to: String::from("MetricKind"),
43 message: Some(
44 "Metric kind should be either \"incremental\" or \"absolute\"".to_string(),
45 ),
46 }),
47 }
48 }
49}
50
51impl IntoLua for StatisticKind {
52 fn into_lua(self, lua: &Lua) -> LuaResult<LuaValue> {
53 let kind = match self {
54 StatisticKind::Summary => "summary",
55 StatisticKind::Histogram => "histogram",
56 };
57 lua.create_string(kind).map(LuaValue::String)
58 }
59}
60
61impl FromLua for StatisticKind {
62 fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
63 match value {
64 LuaValue::String(s) if s == "summary" => Ok(StatisticKind::Summary),
65 LuaValue::String(s) if s == "histogram" => Ok(StatisticKind::Histogram),
66 _ => Err(LuaError::FromLuaConversionError {
67 from: value.type_name(),
68 to: String::from("StatisticKind"),
69 message: Some(
70 "Statistic kind should be either \"summary\" or \"histogram\"".to_string(),
71 ),
72 }),
73 }
74 }
75}
76
77impl FromLua for TagValueSet {
78 fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
79 match value {
80 LuaValue::Nil => Ok(Self::Single(TagValue::Bare)),
81 LuaValue::Table(table) => {
82 let mut string_values: Vec<String> = vec![];
83 for value in table.sequence_values() {
84 match value {
85 Ok(value) => string_values.push(value),
86 Err(_) => unimplemented!(),
87 }
88 }
89 Ok(Self::from(string_values))
90 }
91 LuaValue::String(x) => Ok(Self::from([x.to_string_lossy().to_string()])),
92 _ => Err(mlua::Error::FromLuaConversionError {
93 from: value.type_name(),
94 to: String::from("metric tag value"),
95 message: None,
96 }),
97 }
98 }
99}
100
101impl FromLua for MetricTags {
102 fn from_lua(value: LuaValue, lua: &Lua) -> LuaResult<Self> {
103 Ok(Self(BTreeMap::from_lua(value, lua)?))
104 }
105}
106
107impl IntoLua for LuaMetricTags {
108 fn into_lua(self, lua: &Lua) -> LuaResult<LuaValue> {
109 if self.multi_value_tags {
110 Ok(LuaValue::Table(lua.create_table_from(
111 self.tags.0.into_iter().map(|(key, value)| {
112 let value: Vec<_> = value
113 .into_iter()
114 .filter_map(|tag_value| tag_value.into_option().into_lua(lua).ok())
115 .collect();
116 (key, value)
117 }),
118 )?))
119 } else {
120 Ok(LuaValue::Table(
121 lua.create_table_from(self.tags.iter_single())?,
122 ))
123 }
124 }
125}
126
127impl IntoLua for LuaMetric {
128 #![allow(clippy::wrong_self_convention)] fn into_lua(self, lua: &Lua) -> LuaResult<LuaValue> {
130 let tbl = lua.create_table()?;
131
132 tbl.raw_set("name", self.metric.name())?;
133 if let Some(namespace) = self.metric.namespace() {
134 tbl.raw_set("namespace", namespace)?;
135 }
136 if let Some(ts) = self.metric.data.time.timestamp {
137 tbl.raw_set("timestamp", timestamp_to_table(lua, ts)?)?;
138 }
139 if let Some(i) = self.metric.data.time.interval_ms {
140 tbl.raw_set("interval_ms", i.get())?;
141 }
142 if let Some(tags) = self.metric.series.tags {
143 tbl.raw_set(
144 "tags",
145 LuaMetricTags {
146 tags,
147 multi_value_tags: self.multi_value_tags,
148 },
149 )?;
150 }
151 tbl.raw_set("kind", self.metric.data.kind)?;
152
153 match self.metric.data.value {
154 MetricValue::Counter { value } => {
155 let counter = lua.create_table()?;
156 counter.raw_set("value", value)?;
157 tbl.raw_set("counter", counter)?;
158 }
159 MetricValue::Gauge { value } => {
160 let gauge = lua.create_table()?;
161 gauge.raw_set("value", value)?;
162 tbl.raw_set("gauge", gauge)?;
163 }
164 MetricValue::Set { values } => {
165 let set = lua.create_table()?;
166 set.raw_set("values", lua.create_sequence_from(values.into_iter())?)?;
167 tbl.raw_set("set", set)?;
168 }
169 MetricValue::Distribution { samples, statistic } => {
170 let distribution = lua.create_table()?;
171 let sample_rates: Vec<_> = samples.iter().map(|s| s.rate).collect();
172 let values: Vec<_> = samples.into_iter().map(|s| s.value).collect();
173 distribution.raw_set("values", values)?;
174 distribution.raw_set("sample_rates", sample_rates)?;
175 distribution.raw_set("statistic", statistic)?;
176 tbl.raw_set("distribution", distribution)?;
177 }
178 MetricValue::AggregatedHistogram {
179 buckets,
180 count,
181 sum,
182 } => {
183 let aggregated_histogram = lua.create_table()?;
184 let counts: Vec<_> = buckets.iter().map(|b| b.count).collect();
185 let buckets: Vec<_> = buckets.into_iter().map(|b| b.upper_limit).collect();
186 aggregated_histogram.raw_set("buckets", buckets)?;
187 aggregated_histogram.raw_set("counts", counts)?;
188 aggregated_histogram.raw_set("count", count)?;
189 aggregated_histogram.raw_set("sum", sum)?;
190 tbl.raw_set("aggregated_histogram", aggregated_histogram)?;
191 }
192 MetricValue::AggregatedSummary {
193 quantiles,
194 count,
195 sum,
196 } => {
197 let aggregated_summary = lua.create_table()?;
198 let values: Vec<_> = quantiles.iter().map(|q| q.value).collect();
199 let quantiles: Vec<_> = quantiles.into_iter().map(|q| q.quantile).collect();
200 aggregated_summary.raw_set("quantiles", quantiles)?;
201 aggregated_summary.raw_set("values", values)?;
202 aggregated_summary.raw_set("count", count)?;
203 aggregated_summary.raw_set("sum", sum)?;
204 tbl.raw_set("aggregated_summary", aggregated_summary)?;
205 }
206 MetricValue::Sketch { sketch } => {
207 let sketch_tbl = match sketch {
208 MetricSketch::AgentDDSketch(ddsketch) => {
209 let sketch_tbl = lua.create_table()?;
210 sketch_tbl.raw_set("type", "ddsketch")?;
211 sketch_tbl.raw_set("count", ddsketch.count())?;
212 sketch_tbl.raw_set("min", ddsketch.min())?;
213 sketch_tbl.raw_set("max", ddsketch.max())?;
214 sketch_tbl.raw_set("sum", ddsketch.sum())?;
215 sketch_tbl.raw_set("avg", ddsketch.avg())?;
216
217 let bin_map = ddsketch.bin_map();
218 sketch_tbl.raw_set("k", bin_map.keys)?;
219 sketch_tbl.raw_set("n", bin_map.counts)?;
220 sketch_tbl
221 }
222 };
223
224 tbl.raw_set("sketch", sketch_tbl)?;
225 }
226 }
227
228 Ok(LuaValue::Table(tbl))
229 }
230}
231
232impl FromLua for Metric {
233 #[allow(clippy::too_many_lines)]
234 fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
235 let table = match &value {
236 LuaValue::Table(table) => table,
237 other => {
238 return Err(LuaError::FromLuaConversionError {
239 from: other.type_name(),
240 to: String::from("Metric"),
241 message: Some("Metric should be a Lua table".to_string()),
242 });
243 }
244 };
245
246 let name: String = table.raw_get("name")?;
247 let timestamp = table
248 .raw_get::<Option<LuaTable>>("timestamp")?
249 .map(table_to_timestamp)
250 .transpose()?;
251 let interval_ms: Option<u32> = table.raw_get("interval_ms")?;
252 let namespace: Option<String> = table.raw_get("namespace")?;
253 let tags: Option<MetricTags> = table.raw_get("tags")?;
254 let kind = table
255 .raw_get::<Option<MetricKind>>("kind")?
256 .unwrap_or(MetricKind::Absolute);
257
258 let value = if let Some(counter) = table.raw_get::<Option<LuaTable>>("counter")? {
259 MetricValue::Counter {
260 value: counter.raw_get("value")?,
261 }
262 } else if let Some(gauge) = table.raw_get::<Option<LuaTable>>("gauge")? {
263 MetricValue::Gauge {
264 value: gauge.raw_get("value")?,
265 }
266 } else if let Some(set) = table.raw_get::<Option<LuaTable>>("set")? {
267 MetricValue::Set {
268 values: set.raw_get("values")?,
269 }
270 } else if let Some(distribution) = table.raw_get::<Option<LuaTable>>("distribution")? {
271 let values: Vec<f64> = distribution.raw_get("values")?;
272 let rates: Vec<u32> = distribution.raw_get("sample_rates")?;
273 MetricValue::Distribution {
274 samples: metric::zip_samples(values, rates),
275 statistic: distribution.raw_get("statistic")?,
276 }
277 } else if let Some(aggregated_histogram) =
278 table.raw_get::<Option<LuaTable>>("aggregated_histogram")?
279 {
280 let counts: Vec<u64> = aggregated_histogram.raw_get("counts")?;
281 let buckets: Vec<f64> = aggregated_histogram.raw_get("buckets")?;
282 let count = counts.iter().sum();
283 MetricValue::AggregatedHistogram {
284 buckets: metric::zip_buckets(buckets, counts),
285 count,
286 sum: aggregated_histogram.raw_get("sum")?,
287 }
288 } else if let Some(aggregated_summary) =
289 table.raw_get::<Option<LuaTable>>("aggregated_summary")?
290 {
291 let quantiles: Vec<f64> = aggregated_summary.raw_get("quantiles")?;
292 let values: Vec<f64> = aggregated_summary.raw_get("values")?;
293 MetricValue::AggregatedSummary {
294 quantiles: metric::zip_quantiles(quantiles, values),
295 count: aggregated_summary.raw_get("count")?,
296 sum: aggregated_summary.raw_get("sum")?,
297 }
298 } else if let Some(sketch) = table.raw_get::<Option<LuaTable>>("sketch")? {
299 let sketch_type: String = sketch.raw_get("type")?;
300 match sketch_type.as_str() {
301 "ddsketch" => {
302 let count: u32 = sketch.raw_get("count")?;
303 let min: f64 = sketch.raw_get("min")?;
304 let max: f64 = sketch.raw_get("max")?;
305 let sum: f64 = sketch.raw_get("sum")?;
306 let avg: f64 = sketch.raw_get("avg")?;
307 let k: Vec<i16> = sketch.raw_get("k")?;
308 let n: Vec<u16> = sketch.raw_get("n")?;
309
310 AgentDDSketch::from_raw(count, min, max, sum, avg, &k, &n)
311 .map(|sketch| MetricValue::Sketch {
312 sketch: MetricSketch::AgentDDSketch(sketch),
313 })
314 .ok_or(LuaError::FromLuaConversionError {
315 from: value.type_name(),
316 to: String::from("Metric"),
317 message: Some(
318 "Invalid structure for converting to AgentDDSketch".to_string(),
319 ),
320 })?
321 }
322 x => {
323 return Err(LuaError::FromLuaConversionError {
324 from: value.type_name(),
325 to: String::from("Metric"),
326 message: Some(format!("Invalid sketch type '{x}' given")),
327 });
328 }
329 }
330 } else {
331 return Err(LuaError::FromLuaConversionError {
332 from: value.type_name(),
333 to: String::from("Metric"),
334 message: Some("Cannot find metric value, expected presence one of \"counter\", \"gauge\", \"set\", \"distribution\", \"aggregated_histogram\", \"aggregated_summary\"".to_string()),
335 });
336 };
337
338 Ok(Metric::new(name, kind, value)
339 .with_namespace(namespace)
340 .with_tags(tags)
341 .with_timestamp(timestamp)
342 .with_interval_ms(interval_ms.and_then(std::num::NonZeroU32::new)))
343 }
344}
345
346#[cfg(test)]
347mod test {
348 use chrono::{Timelike, Utc, offset::TimeZone};
349 use vector_common::assert_event_data_eq;
350
351 use super::*;
352
353 fn assert_metric(metric: Metric, multi_value_tags: bool, assertions: Vec<&'static str>) {
354 let lua = Lua::new();
355 lua.globals()
356 .set(
357 "metric",
358 LuaMetric {
359 metric,
360 multi_value_tags,
361 },
362 )
363 .unwrap();
364
365 for assertion in assertions {
366 assert!(
367 lua.load(assertion).eval::<bool>().expect(assertion),
368 "{}",
369 assertion
370 );
371 }
372 }
373
374 #[test]
375 fn into_lua_counter_full() {
376 let metric = Metric::new(
377 "example counter",
378 MetricKind::Incremental,
379 MetricValue::Counter { value: 1.0 },
380 )
381 .with_namespace(Some("namespace_example"))
382 .with_tags(Some(crate::metric_tags!("example tag" => "example value")))
383 .with_timestamp(Some(
384 Utc.with_ymd_and_hms(2018, 11, 14, 8, 9, 10)
385 .single()
386 .and_then(|t| t.with_nanosecond(11))
387 .expect("invalid timestamp"),
388 ));
389
390 assert_metric(
391 metric.clone(),
392 false,
393 vec![
394 "type(metric) == 'table'",
395 "metric.name == 'example counter'",
396 "metric.namespace == 'namespace_example'",
397 "type(metric.timestamp) == 'table'",
398 "metric.timestamp.year == 2018",
399 "metric.timestamp.month == 11",
400 "metric.timestamp.day == 14",
401 "metric.timestamp.hour == 8",
402 "metric.timestamp.min == 9",
403 "metric.timestamp.sec == 10",
404 "type(metric.tags) == 'table'",
405 "metric.tags['example tag'] == 'example value'",
406 "metric.kind == 'incremental'",
407 "type(metric.counter) == 'table'",
408 "metric.counter.value == 1",
409 ],
410 );
411 assert_metric(
412 metric,
413 true,
414 vec![
415 "type(metric) == 'table'",
416 "metric.name == 'example counter'",
417 "metric.namespace == 'namespace_example'",
418 "type(metric.timestamp) == 'table'",
419 "metric.timestamp.year == 2018",
420 "metric.timestamp.month == 11",
421 "metric.timestamp.day == 14",
422 "metric.timestamp.hour == 8",
423 "metric.timestamp.min == 9",
424 "metric.timestamp.sec == 10",
425 "type(metric.tags) == 'table'",
426 "metric.tags['example tag'][1] == 'example value'",
427 "metric.kind == 'incremental'",
428 "type(metric.counter) == 'table'",
429 "metric.counter.value == 1",
430 ],
431 );
432 }
433
434 #[test]
435 fn read_multi_value_tag() {
436 let metric = Metric::new(
437 "example counter",
438 MetricKind::Incremental,
439 MetricValue::Counter { value: 1.0 },
440 )
441 .with_tags(Some(MetricTags(BTreeMap::from([(
442 "example tag".to_string(),
443 TagValueSet::from(vec![
444 TagValue::from("a".to_string()),
445 TagValue::from("b".to_string()),
446 ]),
447 )]))));
448
449 assert_metric(
450 metric,
451 true,
452 vec![
453 "type(metric.tags) == 'table'",
454 "metric.tags['example tag'][1] == 'a'",
455 "metric.tags['example tag'][2] == 'b'",
456 ],
457 );
458 }
459
460 #[test]
461 fn into_lua_counter_minimal() {
462 let metric = Metric::new(
463 "example counter",
464 MetricKind::Absolute,
465 MetricValue::Counter {
466 value: 0.577_215_66,
467 },
468 );
469
470 for multi_value_tags in [false, true] {
471 assert_metric(
472 metric.clone(),
473 multi_value_tags,
474 vec![
475 "metric.timestamp == nil",
476 "metric.tags == nil",
477 "metric.kind == 'absolute'",
478 "metric.counter.value == 0.57721566",
479 ],
480 );
481 }
482 }
483
484 #[test]
485 fn into_lua_gauge() {
486 let metric = Metric::new(
487 "example gauge",
488 MetricKind::Absolute,
489 MetricValue::Gauge { value: 1.618_033_9 },
490 );
491 assert_metric(
492 metric,
493 false,
494 vec!["metric.gauge.value == 1.6180339", "metric.counter == nil"],
495 );
496 }
497
498 #[test]
499 fn into_lua_set() {
500 let metric = Metric::new(
501 "example set",
502 MetricKind::Incremental,
503 MetricValue::Set {
504 values: vec!["value".into(), "another value".into()]
505 .into_iter()
506 .collect(),
507 },
508 );
509 assert_metric(
510 metric,
511 false,
512 vec![
513 "type(metric.set) == 'table'",
514 "type(metric.set.values) == 'table'",
515 "#metric.set.values == 2",
516 "metric.set.values[1] == 'another value'",
517 "metric.set.values[2] == 'value'",
518 ],
519 );
520 }
521
522 #[test]
523 fn into_lua_distribution() {
524 let metric = Metric::new(
525 "example distribution",
526 MetricKind::Incremental,
527 MetricValue::Distribution {
528 samples: crate::samples![1.0 => 10, 1.0 => 20],
529 statistic: StatisticKind::Histogram,
530 },
531 );
532 assert_metric(
533 metric,
534 false,
535 vec![
536 "type(metric.distribution) == 'table'",
537 "#metric.distribution.values == 2",
538 "metric.distribution.values[1] == 1",
539 "metric.distribution.values[2] == 1",
540 "#metric.distribution.sample_rates == 2",
541 "metric.distribution.sample_rates[1] == 10",
542 "metric.distribution.sample_rates[2] == 20",
543 ],
544 );
545 }
546
547 #[test]
548 fn into_lua_aggregated_histogram() {
549 let metric = Metric::new(
550 "example histogram",
551 MetricKind::Incremental,
552 MetricValue::AggregatedHistogram {
553 buckets: crate::buckets![1.0 => 20, 2.0 => 10, 4.0 => 45, 8.0 => 12],
554 count: 87,
555 sum: 975.2,
556 },
557 );
558 assert_metric(
559 metric,
560 false,
561 vec![
562 "type(metric.aggregated_histogram) == 'table'",
563 "#metric.aggregated_histogram.buckets == 4",
564 "metric.aggregated_histogram.buckets[1] == 1",
565 "metric.aggregated_histogram.buckets[4] == 8",
566 "#metric.aggregated_histogram.counts == 4",
567 "metric.aggregated_histogram.counts[1] == 20",
568 "metric.aggregated_histogram.counts[4] == 12",
569 "metric.aggregated_histogram.count == 87",
570 "metric.aggregated_histogram.sum == 975.2",
571 ],
572 );
573 }
574
575 #[test]
576 fn into_lua_aggregated_summary() {
577 let metric = Metric::new(
578 "example summary",
579 MetricKind::Incremental,
580 MetricValue::AggregatedSummary {
581 quantiles: crate::quantiles![
582 0.1 => 2.0, 0.25 => 3.0, 0.5 => 5.0, 0.75 => 8.0, 0.9 => 7.0, 0.99 => 9.0, 1.0 => 10.0
583 ],
584 count: 197,
585 sum: 975.2,
586 },
587 );
588
589 assert_metric(
590 metric,
591 false,
592 vec![
593 "type(metric.aggregated_summary) == 'table'",
594 "#metric.aggregated_summary.quantiles == 7",
595 "metric.aggregated_summary.quantiles[2] == 0.25",
596 "#metric.aggregated_summary.values == 7",
597 "metric.aggregated_summary.values[3] == 5",
598 "metric.aggregated_summary.count == 197",
599 "metric.aggregated_summary.sum == 975.2",
600 ],
601 );
602 }
603
604 #[test]
605 fn from_lua_counter_minimal() {
606 let value = r#"{
607 name = "example counter",
608 counter = {
609 value = 0.57721566
610 }
611 }"#;
612 let expected = Metric::new(
613 "example counter",
614 MetricKind::Absolute,
615 MetricValue::Counter {
616 value: 0.577_215_66,
617 },
618 );
619 assert_event_data_eq!(Lua::new().load(value).eval::<Metric>().unwrap(), expected);
620 }
621
622 #[test]
623 fn from_lua_counter_full() {
624 let value = r#"{
625 name = "example counter",
626 namespace = "example_namespace",
627 timestamp = {
628 year = 2018,
629 month = 11,
630 day = 14,
631 hour = 8,
632 min = 9,
633 sec = 10
634 },
635 tags = {
636 ["example tag"] = "example value"
637 },
638 kind = "incremental",
639 counter = {
640 value = 1
641 }
642 }"#;
643 let expected = Metric::new(
644 "example counter",
645 MetricKind::Incremental,
646 MetricValue::Counter { value: 1.0 },
647 )
648 .with_namespace(Some("example_namespace"))
649 .with_tags(Some(crate::metric_tags!("example tag" => "example value")))
650 .with_timestamp(Some(
651 Utc.with_ymd_and_hms(2018, 11, 14, 8, 9, 10)
652 .single()
653 .expect("invalid timestamp"),
654 ));
655 assert_event_data_eq!(Lua::new().load(value).eval::<Metric>().unwrap(), expected);
656 }
657
658 #[test]
659 fn set_multi_valued_tags() {
660 let value = r#"{
661 name = "example counter",
662 namespace = "example_namespace",
663 timestamp = {
664 year = 2018,
665 month = 11,
666 day = 14,
667 hour = 8,
668 min = 9,
669 sec = 10
670 },
671 tags = {
672 ["example tag"] = {"a", "b"}
673 },
674 kind = "incremental",
675 counter = {
676 value = 1
677 }
678 }"#;
679 let expected = Metric::new(
680 "example counter",
681 MetricKind::Incremental,
682 MetricValue::Counter { value: 1.0 },
683 )
684 .with_namespace(Some("example_namespace"))
685 .with_tags(Some(MetricTags(BTreeMap::from([(
686 "example tag".to_string(),
687 TagValueSet::from(vec![
688 TagValue::from("a".to_string()),
689 TagValue::from("b".to_string()),
690 ]),
691 )]))))
692 .with_timestamp(Some(
693 Utc.with_ymd_and_hms(2018, 11, 14, 8, 9, 10)
694 .single()
695 .expect("invalid timestamp"),
696 ));
697 assert_event_data_eq!(Lua::new().load(value).eval::<Metric>().unwrap(), expected);
698 }
699
700 #[test]
701 fn from_lua_gauge() {
702 let value = r#"{
703 name = "example gauge",
704 gauge = {
705 value = 1.6180339
706 }
707 }"#;
708 let expected = Metric::new(
709 "example gauge",
710 MetricKind::Absolute,
711 MetricValue::Gauge { value: 1.618_033_9 },
712 );
713 assert_event_data_eq!(Lua::new().load(value).eval::<Metric>().unwrap(), expected);
714 }
715
716 #[test]
717 fn from_lua_set() {
718 let value = r#"{
719 name = "example set",
720 set = {
721 values = { "value", "another value" }
722 }
723 }"#;
724 let expected = Metric::new(
725 "example set",
726 MetricKind::Absolute,
727 MetricValue::Set {
728 values: vec!["value".into(), "another value".into()]
729 .into_iter()
730 .collect(),
731 },
732 );
733 assert_event_data_eq!(Lua::new().load(value).eval::<Metric>().unwrap(), expected);
734 }
735
736 #[test]
737 fn from_lua_distribution() {
738 let value = r#"{
739 name = "example distribution",
740 distribution = {
741 values = { 1.0, 1.0 },
742 sample_rates = { 10, 20 },
743 statistic = "histogram"
744 }
745 }"#;
746 let expected = Metric::new(
747 "example distribution",
748 MetricKind::Absolute,
749 MetricValue::Distribution {
750 samples: crate::samples![1.0 => 10, 1.0 => 20],
751 statistic: StatisticKind::Histogram,
752 },
753 );
754 assert_event_data_eq!(Lua::new().load(value).eval::<Metric>().unwrap(), expected);
755 }
756
757 #[test]
758 fn from_lua_aggregated_histogram() {
759 let value = r#"{
760 name = "example histogram",
761 aggregated_histogram = {
762 buckets = { 1, 2, 4, 8 },
763 counts = { 20, 10, 45, 12 },
764 sum = 975.2
765 }
766 }"#;
767 let expected = Metric::new(
768 "example histogram",
769 MetricKind::Absolute,
770 MetricValue::AggregatedHistogram {
771 buckets: crate::buckets![1.0 => 20, 2.0 => 10, 4.0 => 45, 8.0 => 12],
772 count: 87,
773 sum: 975.2,
774 },
775 );
776 assert_event_data_eq!(Lua::new().load(value).eval::<Metric>().unwrap(), expected);
777 }
778
779 #[test]
780 fn from_lua_aggregated_summary() {
781 let value = r#"{
782 name = "example summary",
783 aggregated_summary = {
784 quantiles = { 0.1, 0.25, 0.5, 0.75, 0.9, 0.99, 1.0 },
785 values = { 2.0, 3.0, 5.0, 8.0, 7.0, 9.0, 10.0 },
786 count = 197,
787 sum = 975.2
788 }
789 }"#;
790 let expected = Metric::new(
791 "example summary",
792 MetricKind::Absolute,
793 MetricValue::AggregatedSummary {
794 quantiles: crate::quantiles![
795 0.1 => 2.0, 0.25 => 3.0, 0.5 => 5.0, 0.75 => 8.0, 0.9 => 7.0, 0.99 => 9.0, 1.0 => 10.0
796 ],
797 count: 197,
798 sum: 975.2,
799 },
800 );
801 assert_event_data_eq!(Lua::new().load(value).eval::<Metric>().unwrap(), expected);
802 }
803}