Skip to main content

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