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)] 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)] 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}