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