vector_core/event/lua/
metric.rs

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