1mod baseline;
21mod builder;
22mod custom;
23mod elapsed_compute;
24mod expression;
25mod value;
26
27use datafusion_common::HashMap;
28pub use datafusion_common::format::{MetricCategory, MetricType};
29use parking_lot::Mutex;
30use std::{
31 borrow::Cow,
32 fmt::{self, Debug, Display},
33 hash::{Hash, Hasher},
34 sync::Arc,
35 vec::IntoIter,
36};
37
38pub use baseline::{BaselineMetrics, RecordOutput, SpillMetrics, SplitMetrics};
41pub use builder::MetricBuilder;
42pub use custom::CustomMetricValue;
43pub use elapsed_compute::{ElapsedComputeFuture, ElapsedComputeFutureExt};
44pub use expression::ExpressionEvaluatorMetrics;
45pub use value::{
46 Count, Gauge, MetricValue, PruningMetrics, RatioMergeStrategy, RatioMetrics,
47 ScopedTimerGuard, Time, Timestamp,
48};
49
50#[derive(Debug)]
77pub struct Metric {
78 value: MetricValue,
80
81 labels: Vec<Label>,
83
84 partition: Option<usize>,
87
88 metric_type: MetricType,
89
90 metric_category: Option<MetricCategory>,
96}
97
98impl Display for Metric {
99 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
100 write!(f, "{}", self.value.name())?;
101
102 let mut iter = self
103 .partition
104 .iter()
105 .map(|partition| Label::new("partition", partition.to_string()))
106 .chain(self.labels().iter().cloned())
107 .peekable();
108
109 if iter.peek().is_some() {
111 write!(f, "{{")?;
112
113 let mut is_first = true;
114 for i in iter {
115 if !is_first {
116 write!(f, ", ")?;
117 } else {
118 is_first = false;
119 }
120
121 write!(f, "{i}")?;
122 }
123
124 write!(f, "}}")?;
125 }
126
127 write!(f, "={}", self.value)
129 }
130}
131
132impl Metric {
133 pub fn new(value: MetricValue, partition: Option<usize>) -> Self {
136 Self {
137 value,
138 labels: vec![],
139 partition,
140 metric_type: MetricType::Dev,
141 metric_category: None,
142 }
143 }
144
145 pub fn new_with_labels(
148 value: MetricValue,
149 partition: Option<usize>,
150 labels: Vec<Label>,
151 ) -> Self {
152 Self {
153 value,
154 labels,
155 partition,
156 metric_type: MetricType::Dev,
157 metric_category: None,
158 }
159 }
160
161 pub fn with_type(mut self, metric_type: MetricType) -> Self {
163 self.metric_type = metric_type;
164 self
165 }
166
167 pub fn with_category(mut self, category: MetricCategory) -> Self {
172 self.metric_category = Some(category);
173 self
174 }
175
176 pub fn with_label(mut self, label: Label) -> Self {
178 self.labels.push(label);
179 self
180 }
181
182 pub fn labels(&self) -> &[Label] {
184 &self.labels
185 }
186
187 pub fn value(&self) -> &MetricValue {
189 &self.value
190 }
191
192 pub fn value_mut(&mut self) -> &mut MetricValue {
194 &mut self.value
195 }
196
197 pub fn partition(&self) -> Option<usize> {
199 self.partition
200 }
201
202 pub fn metric_type(&self) -> MetricType {
204 self.metric_type
205 }
206
207 pub fn metric_category(&self) -> Option<MetricCategory> {
211 self.metric_category
212 }
213}
214
215#[derive(Default, Debug, Clone)]
217pub struct MetricsSet {
218 metrics: Vec<Arc<Metric>>,
219}
220
221impl MetricsSet {
222 pub fn new() -> Self {
224 Default::default()
225 }
226
227 pub fn push(&mut self, metric: Arc<Metric>) {
229 self.metrics.push(metric)
230 }
231
232 pub fn iter(&self) -> impl Iterator<Item = &Arc<Metric>> {
234 self.metrics.iter()
235 }
236
237 pub fn output_rows(&self) -> Option<usize> {
240 self.sum(|metric| matches!(metric.value(), MetricValue::OutputRows(_)))
241 .map(|v| v.as_usize())
242 }
243
244 pub fn spill_count(&self) -> Option<usize> {
247 self.sum(|metric| matches!(metric.value(), MetricValue::SpillCount(_)))
248 .map(|v| v.as_usize())
249 }
250
251 pub fn spilled_bytes(&self) -> Option<usize> {
254 self.sum(|metric| matches!(metric.value(), MetricValue::SpilledBytes(_)))
255 .map(|v| v.as_usize())
256 }
257
258 pub fn spilled_rows(&self) -> Option<usize> {
261 self.sum(|metric| matches!(metric.value(), MetricValue::SpilledRows(_)))
262 .map(|v| v.as_usize())
263 }
264
265 pub fn elapsed_compute(&self) -> Option<usize> {
268 self.sum(|metric| matches!(metric.value(), MetricValue::ElapsedCompute(_)))
269 .map(|v| v.as_usize())
270 }
271
272 pub fn sum<F>(&self, mut f: F) -> Option<MetricValue>
276 where
277 F: FnMut(&Metric) -> bool,
278 {
279 let mut iter = self
280 .metrics
281 .iter()
282 .filter(|metric| f(metric.as_ref()))
283 .peekable();
284
285 let mut accum = match iter.peek() {
286 None => {
287 return None;
288 }
289 Some(metric) => metric.value().new_empty(),
290 };
291
292 iter.for_each(|metric| accum.aggregate(metric.value()));
293
294 Some(accum)
295 }
296
297 pub fn sum_by_name(&self, metric_name: &str) -> Option<MetricValue> {
300 self.sum(|m| match m.value() {
301 MetricValue::Count { name, .. } => name == metric_name,
302 MetricValue::Time { name, .. } => name == metric_name,
303 MetricValue::OutputRows(_) => false,
304 MetricValue::ElapsedCompute(_) => false,
305 MetricValue::SpillCount(_) => false,
306 MetricValue::SpilledBytes(_) => false,
307 MetricValue::OutputBytes(_) => false,
308 MetricValue::OutputBatches(_) => false,
309 MetricValue::SpilledRows(_) => false,
310 MetricValue::CurrentMemoryUsage(_) => false,
311 MetricValue::Gauge { name, .. } => name == metric_name,
312 MetricValue::PeakMemoryUsage { name, .. } => name == metric_name,
313 MetricValue::StartTimestamp(_) => false,
314 MetricValue::EndTimestamp(_) => false,
315 MetricValue::PruningMetrics { name, .. } => name == metric_name,
316 MetricValue::Ratio { name, .. } => name == metric_name,
317 MetricValue::Custom { .. } => false,
318 })
319 }
320
321 pub fn aggregate_by_name(&self) -> Self {
326 let mut map = HashMap::new();
327
328 for metric in &self.metrics {
330 let key = metric.value.name();
331 map.entry(key)
332 .and_modify(|accum: &mut Metric| {
333 accum.value_mut().aggregate(metric.value());
334 })
335 .or_insert_with(|| {
336 let partition = None;
338 let mut accum = Metric::new(metric.value().new_empty(), partition)
339 .with_type(metric.metric_type());
340 if let Some(cat) = metric.metric_category() {
341 accum = accum.with_category(cat);
342 }
343 accum.value_mut().aggregate(metric.value());
344 accum
345 });
346 }
347
348 let new_metrics = map
349 .into_iter()
350 .map(|(_k, v)| Arc::new(v))
351 .collect::<Vec<_>>();
352
353 Self {
354 metrics: new_metrics,
355 }
356 }
357
358 pub fn sorted_for_display(mut self) -> Self {
360 self.metrics.sort_unstable_by_key(|metric| {
361 (
362 metric.value().display_sort_key(),
363 metric.value().name().to_owned(),
364 )
365 });
366 self
367 }
368
369 pub fn timestamps_removed(self) -> Self {
371 let Self { metrics } = self;
372
373 let metrics = metrics
374 .into_iter()
375 .filter(|m| !m.value.is_timestamp())
376 .collect::<Vec<_>>();
377
378 Self { metrics }
379 }
380
381 pub fn filter_by_metric_types(self, allowed: &[MetricType]) -> Self {
384 if allowed.is_empty() {
385 return Self { metrics: vec![] };
386 }
387
388 let metrics = self
389 .metrics
390 .into_iter()
391 .filter(|metric| allowed.contains(&metric.metric_type()))
392 .collect::<Vec<_>>();
393 Self { metrics }
394 }
395
396 pub fn filter_by_categories(self, allowed: &[MetricCategory]) -> Self {
405 if allowed.is_empty() {
406 return Self { metrics: vec![] };
407 }
408
409 let metrics = self
410 .metrics
411 .into_iter()
412 .filter(|metric| {
413 let cat = metric
414 .metric_category()
415 .unwrap_or(MetricCategory::Uncategorized);
416 allowed.contains(&cat)
417 })
418 .collect::<Vec<_>>();
419 Self { metrics }
420 }
421
422 pub fn filter_by_names(self, names: &[String]) -> Self {
425 if names.is_empty() {
426 return Self { metrics: vec![] };
427 }
428
429 let metrics = self
430 .metrics
431 .into_iter()
432 .filter(|metric| names.iter().any(|name| name == metric.value().name()))
433 .collect::<Vec<_>>();
434 Self { metrics }
435 }
436}
437
438impl Display for MetricsSet {
439 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
441 let mut is_first = true;
442 for i in self.metrics.iter() {
443 if !is_first {
444 write!(f, ", ")?;
445 } else {
446 is_first = false;
447 }
448
449 write!(f, "{i}")?;
450 }
451 Ok(())
452 }
453}
454
455impl IntoIterator for MetricsSet {
456 type Item = Arc<Metric>;
457 type IntoIter = IntoIter<Self::Item>;
458
459 fn into_iter(self) -> Self::IntoIter {
460 self.metrics.into_iter()
461 }
462}
463
464impl<'a> IntoIterator for &'a MetricsSet {
465 type Item = &'a Arc<Metric>;
466 type IntoIter = std::slice::Iter<'a, Arc<Metric>>;
467
468 fn into_iter(self) -> Self::IntoIter {
469 self.metrics.iter()
470 }
471}
472
473impl Extend<Arc<Metric>> for MetricsSet {
474 fn extend<I: IntoIterator<Item = Arc<Metric>>>(&mut self, iter: I) {
475 self.metrics.extend(iter);
476 }
477}
478
479impl FromIterator<Arc<Metric>> for MetricsSet {
480 fn from_iter<T: IntoIterator<Item = Arc<Metric>>>(iter: T) -> Self {
481 Self {
482 metrics: iter.into_iter().collect(),
483 }
484 }
485}
486
487#[derive(Default, Debug, Clone)]
496pub struct ExecutionPlanMetricsSet {
497 inner: Arc<Mutex<MetricsSet>>,
498}
499
500impl ExecutionPlanMetricsSet {
501 pub fn new() -> Self {
503 Self {
504 inner: Arc::new(Mutex::new(MetricsSet::new())),
505 }
506 }
507
508 pub fn register(&self, metric: Arc<Metric>) {
510 self.inner.lock().push(metric)
511 }
512
513 pub fn clone_inner(&self) -> MetricsSet {
515 let guard = self.inner.lock();
516 (*guard).clone()
517 }
518}
519
520impl From<MetricsSet> for ExecutionPlanMetricsSet {
521 fn from(metrics: MetricsSet) -> Self {
522 Self {
523 inner: Arc::new(Mutex::new(metrics)),
524 }
525 }
526}
527
528#[derive(Debug, Clone, PartialEq, Eq, Hash)]
544pub struct Label {
545 name: LabelValue,
546 value: LabelValue,
547}
548
549impl Label {
550 pub fn new(name: impl Into<LabelValue>, value: impl Into<LabelValue>) -> Self {
552 let name = name.into();
553 let value = value.into();
554 Self { name, value }
555 }
556
557 pub fn name(&self) -> &str {
559 self.name.as_str()
560 }
561
562 pub fn value(&self) -> &str {
564 self.value.as_str()
565 }
566}
567
568impl Display for Label {
569 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
570 write!(f, "{}={}", self.name, self.value)
571 }
572}
573
574#[derive(Clone)]
581pub struct LabelValue(LabelValueInner);
582
583#[derive(Clone)]
589enum LabelValueInner {
590 Static(&'static str),
591 Shared(Arc<str>),
592}
593
594impl LabelValue {
595 pub fn as_str(&self) -> &str {
597 match &self.0 {
598 LabelValueInner::Static(value) => value,
599 LabelValueInner::Shared(value) => value.as_ref(),
600 }
601 }
602}
603
604impl From<&'static str> for LabelValue {
605 fn from(value: &'static str) -> Self {
606 Self(LabelValueInner::Static(value))
607 }
608}
609
610impl From<String> for LabelValue {
611 fn from(value: String) -> Self {
612 Self(LabelValueInner::Shared(Arc::from(value)))
613 }
614}
615
616impl From<Arc<str>> for LabelValue {
617 fn from(value: Arc<str>) -> Self {
618 Self(LabelValueInner::Shared(value))
619 }
620}
621
622impl From<Cow<'static, str>> for LabelValue {
623 fn from(value: Cow<'static, str>) -> Self {
624 match value {
625 Cow::Borrowed(value) => value.into(),
626 Cow::Owned(value) => value.into(),
627 }
628 }
629}
630
631impl PartialEq for LabelValue {
632 fn eq(&self, other: &Self) -> bool {
633 self.as_str() == other.as_str()
634 }
635}
636
637impl Eq for LabelValue {}
638
639impl Hash for LabelValue {
640 fn hash<H: Hasher>(&self, state: &mut H) {
641 self.as_str().hash(state);
642 }
643}
644
645impl Debug for LabelValue {
646 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
647 Debug::fmt(self.as_str(), f)
648 }
649}
650
651impl Display for LabelValue {
652 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
653 Display::fmt(self.as_str(), f)
654 }
655}
656
657#[cfg(test)]
658mod tests {
659 use std::time::Duration;
660
661 use chrono::{TimeZone, Utc};
662
663 use super::*;
664
665 #[test]
666 fn test_display_no_labels_no_partition() {
667 let count = Count::new();
668 count.add(33);
669 let value = MetricValue::OutputRows(count);
670 let partition = None;
671 let metric = Metric::new(value, partition);
672
673 assert_eq!("output_rows=33", metric.to_string())
674 }
675
676 #[test]
677 fn test_display_no_labels_with_partition() {
678 let count = Count::new();
679 count.add(44);
680 let value = MetricValue::OutputRows(count);
681 let partition = Some(1);
682 let metric = Metric::new(value, partition);
683
684 assert_eq!("output_rows{partition=1}=44", metric.to_string())
685 }
686
687 #[test]
688 fn test_display_labels_no_partition() {
689 let count = Count::new();
690 count.add(55);
691 let value = MetricValue::OutputRows(count);
692 let partition = None;
693 let label = Label::new("foo", "bar");
694 let metric = Metric::new_with_labels(value, partition, vec![label]);
695
696 assert_eq!("output_rows{foo=bar}=55", metric.to_string())
697 }
698
699 #[test]
700 fn test_display_labels_and_partition() {
701 let count = Count::new();
702 count.add(66);
703 let value = MetricValue::OutputRows(count);
704 let partition = Some(2);
705 let label = Label::new("foo", "bar");
706 let metric = Metric::new_with_labels(value, partition, vec![label]);
707
708 assert_eq!("output_rows{partition=2, foo=bar}=66", metric.to_string())
709 }
710
711 #[test]
712 fn test_label_owned_and_borrowed_values_are_equal() {
713 let borrowed = Label::new("foo", "bar");
714 let owned = Label::new("foo".to_string(), "bar".to_string());
715 let shared = Label::new("foo", Arc::<str>::from("bar"));
716
717 assert_eq!(borrowed, owned);
718 assert_eq!(borrowed, shared);
719 assert_eq!(borrowed.to_string(), owned.to_string());
720 assert_eq!(borrowed.to_string(), shared.to_string());
721 }
722
723 #[test]
724 fn test_output_rows() {
725 let metrics = ExecutionPlanMetricsSet::new();
726 assert!(metrics.clone_inner().output_rows().is_none());
727
728 let partition = 1;
729 let output_rows = MetricBuilder::new(&metrics).output_rows(partition);
730 output_rows.add(13);
731
732 let output_rows = MetricBuilder::new(&metrics).output_rows(partition + 1);
733 output_rows.add(7);
734 assert_eq!(metrics.clone_inner().output_rows().unwrap(), 20);
735 }
736
737 #[test]
738 fn test_elapsed_compute() {
739 let metrics = ExecutionPlanMetricsSet::new();
740 assert!(metrics.clone_inner().elapsed_compute().is_none());
741
742 let partition = 1;
743 let elapsed_compute = MetricBuilder::new(&metrics).elapsed_compute(partition);
744 elapsed_compute.add_duration(Duration::from_nanos(1234));
745
746 let elapsed_compute = MetricBuilder::new(&metrics).elapsed_compute(partition + 1);
747 elapsed_compute.add_duration(Duration::from_nanos(6));
748 assert_eq!(metrics.clone_inner().elapsed_compute().unwrap(), 1240);
749 }
750
751 #[test]
752 fn test_sum() {
753 let metrics = ExecutionPlanMetricsSet::new();
754
755 let count1 = MetricBuilder::new(&metrics)
756 .with_new_label("foo", "bar")
757 .counter("my_counter", 1);
758 count1.add(1);
759
760 let count2 = MetricBuilder::new(&metrics).counter("my_counter", 2);
761 count2.add(2);
762
763 let metrics = metrics.clone_inner();
764 assert!(metrics.sum(|_| false).is_none());
765
766 let expected_count = Count::new();
767 expected_count.add(3);
768 let expected_sum = MetricValue::Count {
769 name: "my_counter".into(),
770 count: expected_count,
771 };
772
773 assert_eq!(metrics.sum(|_| true), Some(expected_sum));
774 }
775
776 #[test]
777 #[should_panic(expected = "Mismatched metric types. Can not aggregate Count")]
778 fn test_bad_sum() {
779 let metrics = ExecutionPlanMetricsSet::new();
781
782 let count = MetricBuilder::new(&metrics).counter("my_metric", 1);
783 count.add(1);
784
785 let time = MetricBuilder::new(&metrics).subset_time("my_metric", 1);
786 time.add_duration(Duration::from_nanos(10));
787
788 metrics.clone_inner().sum(|_| true);
790 }
791
792 #[test]
793 fn test_aggregate_by_name() {
794 let metrics = ExecutionPlanMetricsSet::new();
795
796 let elapsed_compute1 = MetricBuilder::new(&metrics)
798 .with_new_label("foo", "bar")
799 .elapsed_compute(1);
800 elapsed_compute1.add_duration(Duration::from_nanos(12));
801
802 let elapsed_compute2 = MetricBuilder::new(&metrics).elapsed_compute(2);
803 elapsed_compute2.add_duration(Duration::from_nanos(34));
804
805 let elapsed_compute3 = MetricBuilder::new(&metrics).elapsed_compute(4);
806 elapsed_compute3.add_duration(Duration::from_nanos(56));
807
808 let output_rows = MetricBuilder::new(&metrics).output_rows(1); output_rows.add(56);
810
811 let aggregated = metrics.clone_inner().aggregate_by_name();
812
813 let elapsed_computes = aggregated
815 .iter()
816 .filter(|metric| matches!(metric.value(), MetricValue::ElapsedCompute(_)))
817 .collect::<Vec<_>>();
818 assert_eq!(elapsed_computes.len(), 1);
819 assert_eq!(elapsed_computes[0].value().as_usize(), 12 + 34 + 56);
820 assert!(elapsed_computes[0].partition().is_none());
821
822 let output_rows = aggregated
824 .iter()
825 .filter(|metric| matches!(metric.value(), MetricValue::OutputRows(_)))
826 .collect::<Vec<_>>();
827 assert_eq!(output_rows.len(), 1);
828 assert_eq!(output_rows[0].value().as_usize(), 56);
829 assert!(output_rows[0].partition.is_none())
830 }
831
832 #[test]
833 #[should_panic(expected = "Mismatched metric types. Can not aggregate Count")]
834 fn test_aggregate_partition_bad_sum() {
835 let metrics = ExecutionPlanMetricsSet::new();
836
837 let count = MetricBuilder::new(&metrics).counter("my_metric", 1);
838 count.add(1);
839
840 let time = MetricBuilder::new(&metrics).subset_time("my_metric", 1);
841 time.add_duration(Duration::from_nanos(10));
842
843 metrics.clone_inner().aggregate_by_name();
845 }
846
847 #[test]
848 fn test_aggregate_partition_timestamps() {
849 let metrics = ExecutionPlanMetricsSet::new();
850
851 let t1 = Utc.timestamp_nanos(1431648000000000);
853 let t2 = Utc.timestamp_nanos(1531648000000000);
855 let t3 = Utc.timestamp_nanos(1631648000000000);
857 let t4 = Utc.timestamp_nanos(1731648000000000);
859
860 let start_timestamp0 = MetricBuilder::new(&metrics).start_timestamp(0);
861 start_timestamp0.set(t1);
862 let end_timestamp0 = MetricBuilder::new(&metrics).end_timestamp(0);
863 end_timestamp0.set(t2);
864 let start_timestamp1 = MetricBuilder::new(&metrics).start_timestamp(0);
865 start_timestamp1.set(t3);
866 let end_timestamp1 = MetricBuilder::new(&metrics).end_timestamp(0);
867 end_timestamp1.set(t4);
868
869 let aggregated = metrics.clone_inner().aggregate_by_name();
871
872 let mut ts = aggregated
873 .iter()
874 .filter(|metric| {
875 matches!(metric.value(), MetricValue::StartTimestamp(_))
876 && metric.labels().is_empty()
877 })
878 .collect::<Vec<_>>();
879 assert_eq!(ts.len(), 1);
880 match ts.remove(0).value() {
881 MetricValue::StartTimestamp(ts) => {
882 assert_eq!(ts.value(), Some(t1));
884 }
885 _ => {
886 panic!("Not a timestamp");
887 }
888 };
889
890 let mut ts = aggregated
891 .iter()
892 .filter(|metric| {
893 matches!(metric.value(), MetricValue::EndTimestamp(_))
894 && metric.labels().is_empty()
895 })
896 .collect::<Vec<_>>();
897 assert_eq!(ts.len(), 1);
898 match ts.remove(0).value() {
899 MetricValue::EndTimestamp(ts) => {
900 assert_eq!(ts.value(), Some(t4));
902 }
903 _ => {
904 panic!("Not a timestamp");
905 }
906 };
907 }
908
909 #[test]
910 fn test_extend() {
911 let mut metrics = MetricsSet::new();
912 let m1 = Arc::new(Metric::new(MetricValue::OutputRows(Count::new()), None));
913 let m2 = Arc::new(Metric::new(MetricValue::SpillCount(Count::new()), None));
914
915 metrics.extend([Arc::clone(&m1), Arc::clone(&m2)]);
916 assert_eq!(metrics.iter().count(), 2);
917
918 let m3 = Arc::new(Metric::new(MetricValue::SpilledBytes(Count::new()), None));
919 metrics.extend(std::iter::once(Arc::clone(&m3)));
920 assert_eq!(metrics.iter().count(), 3);
921 }
922
923 #[test]
924 fn test_collect() {
925 let m1 = Arc::new(Metric::new(MetricValue::OutputRows(Count::new()), None));
926 let m2 = Arc::new(Metric::new(MetricValue::SpillCount(Count::new()), None));
927
928 let metrics: MetricsSet =
929 vec![Arc::clone(&m1), Arc::clone(&m2)].into_iter().collect();
930 assert_eq!(metrics.iter().count(), 2);
931
932 let empty: MetricsSet = std::iter::empty().collect();
933 assert_eq!(empty.iter().count(), 0);
934 }
935
936 #[test]
937 fn test_into_iterator_by_ref() {
938 let mut metrics = MetricsSet::new();
939 metrics.push(Arc::new(Metric::new(
940 MetricValue::OutputRows(Count::new()),
941 None,
942 )));
943 metrics.push(Arc::new(Metric::new(
944 MetricValue::SpillCount(Count::new()),
945 None,
946 )));
947
948 let mut count = 0;
949 for _m in &metrics {
950 count += 1;
951 }
952 assert_eq!(count, 2);
953 }
954
955 #[test]
956 fn test_sorted_for_display() {
957 let metrics = ExecutionPlanMetricsSet::new();
958 MetricBuilder::new(&metrics).end_timestamp(0);
959 MetricBuilder::new(&metrics).start_timestamp(0);
960 MetricBuilder::new(&metrics).elapsed_compute(0);
961 MetricBuilder::new(&metrics).counter("the_second_counter", 0);
962 MetricBuilder::new(&metrics).counter("the_counter", 0);
963 MetricBuilder::new(&metrics).counter("the_third_counter", 0);
964 MetricBuilder::new(&metrics).subset_time("the_time", 0);
965 MetricBuilder::new(&metrics).output_rows(0);
966 let metrics = metrics.clone_inner();
967
968 fn metric_names(metrics: &MetricsSet) -> String {
969 let n = metrics.iter().map(|m| m.value().name()).collect::<Vec<_>>();
970 n.join(", ")
971 }
972
973 assert_eq!(
974 "end_timestamp, start_timestamp, elapsed_compute, the_second_counter, the_counter, the_third_counter, the_time, output_rows",
975 metric_names(&metrics)
976 );
977
978 let metrics = metrics.sorted_for_display();
979 assert_eq!(
980 "output_rows, elapsed_compute, the_counter, the_second_counter, the_third_counter, the_time, start_timestamp, end_timestamp",
981 metric_names(&metrics)
982 );
983 }
984
985 #[test]
986 fn test_filter_by_names() {
987 let metrics = ExecutionPlanMetricsSet::new();
988 MetricBuilder::new(&metrics).output_rows(0);
989 MetricBuilder::new(&metrics).counter("custom_counter", 0);
990
991 assert!(
992 metrics
993 .clone_inner()
994 .filter_by_names(&[])
995 .iter()
996 .next()
997 .is_none()
998 );
999
1000 let names = vec!["output_rows".to_string()];
1001 let filtered = metrics.clone_inner().filter_by_names(&names);
1002
1003 assert_eq!(filtered.iter().count(), 1);
1004 assert_eq!(
1005 filtered.iter().next().unwrap().value().name(),
1006 "output_rows"
1007 );
1008 }
1009}