vector_core/event/lua/
metric.rs

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)] // this trait is defined by mlua
25    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)] // this trait is defined by mlua
128    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}