/build/source/nativelink-metric-collector/src/metrics_visitors.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2024 The NativeLink Authors. All rights reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | use std::borrow::Cow; |
16 | | use std::fmt::Debug; |
17 | | |
18 | | use nativelink_metric::MetricKind; |
19 | | use serde::Serialize; |
20 | | use tracing::field::{Field, Visit}; |
21 | | |
22 | | use crate::metrics_collection::{CollectedMetricPrimitive, CollectedMetricPrimitiveValue}; |
23 | | |
24 | | /// The type of the collected primitive metric. |
25 | | #[derive(Default, Debug, Serialize)] |
26 | | pub enum CollectionKind { |
27 | | #[default] |
28 | | Counter = 0, |
29 | | String = 1, |
30 | | } |
31 | | |
32 | | impl From<MetricKind> for CollectionKind { |
33 | 14 | fn from(kind: MetricKind) -> Self { |
34 | 14 | match kind { |
35 | 6 | MetricKind::Counter => CollectionKind::Counter, |
36 | 8 | MetricKind::String => CollectionKind::String, |
37 | 0 | _ => CollectionKind::String, |
38 | | } |
39 | 14 | } |
40 | | } |
41 | | |
42 | | /// The final-metric primitive value and type that was collected. |
43 | | #[derive(Debug)] |
44 | | enum ValueWithPrimitiveType { |
45 | | String(String), |
46 | | U64(u64), |
47 | | } |
48 | | |
49 | | impl Default for ValueWithPrimitiveType { |
50 | 14 | fn default() -> Self { |
51 | 14 | ValueWithPrimitiveType::U64(0) |
52 | 14 | } |
53 | | } |
54 | | |
55 | | /// An intermediate structed that will have it's contents populated |
56 | | /// by the `tracing` layer for a given field. |
57 | | /// This is done by implementing the `Visit` trait and asking the |
58 | | /// `tracing` library to visit the fields of the captured event |
59 | | /// and populate this struct. |
60 | | #[derive(Default, Debug)] |
61 | | pub struct MetricDataVisitor { |
62 | | pub name: String, |
63 | | value: ValueWithPrimitiveType, |
64 | | help: String, |
65 | | value_type: Option<CollectionKind>, |
66 | | } |
67 | | |
68 | | impl From<MetricDataVisitor> for CollectedMetricPrimitive { |
69 | 14 | fn from(visitor: MetricDataVisitor) -> Self { |
70 | 14 | let (value, derived_type) = match visitor.value { |
71 | 8 | ValueWithPrimitiveType::String(s) => ( |
72 | 8 | CollectedMetricPrimitiveValue::String(Cow::Owned(s)), |
73 | 8 | CollectionKind::String, |
74 | 8 | ), |
75 | 6 | ValueWithPrimitiveType::U64(u) => ( |
76 | 6 | CollectedMetricPrimitiveValue::Counter(u), |
77 | 6 | CollectionKind::Counter, |
78 | 6 | ), |
79 | | }; |
80 | 14 | CollectedMetricPrimitive { |
81 | 14 | value: Some(value), |
82 | 14 | help: visitor.help, |
83 | 14 | value_type: visitor.value_type.unwrap_or(derived_type), |
84 | 14 | } |
85 | 14 | } |
86 | | } |
87 | | |
88 | | impl Visit for MetricDataVisitor { |
89 | 0 | fn record_debug(&mut self, _field: &Field, _value: &dyn Debug) {} |
90 | | |
91 | 0 | fn record_f64(&mut self, field: &Field, value: f64) { |
92 | 0 | if field.name() == "__value" { Branch (92:12): [True: 0, False: 0]
Branch (92:12): [Folded - Ignored]
|
93 | 0 | self.value = ValueWithPrimitiveType::String(value.to_string()); |
94 | 0 | } |
95 | 0 | } |
96 | 0 | fn record_i64(&mut self, field: &Field, value: i64) { |
97 | 0 | if field.name() == "__value" { Branch (97:12): [True: 0, False: 0]
Branch (97:12): [Folded - Ignored]
|
98 | 0 | match u64::try_from(value) { |
99 | 0 | Ok(v) => self.value = ValueWithPrimitiveType::U64(v), |
100 | 0 | Err(_) => self.value = ValueWithPrimitiveType::String(value.to_string()), |
101 | | } |
102 | 0 | } |
103 | 0 | } |
104 | 20 | fn record_u64(&mut self, field: &Field, value: u64) { |
105 | 20 | match field.name() { |
106 | 20 | "__value" => self.value = ValueWithPrimitiveType::U64(value)6 , |
107 | 14 | "__type" => self.value_type = Some(MetricKind::from(value).into()), |
108 | 0 | "__help" => self.help = value.to_string(), |
109 | 0 | "__name" => self.name = value.to_string(), |
110 | 0 | field => panic!("UNKNOWN FIELD {field}"), |
111 | | } |
112 | 20 | } |
113 | 0 | fn record_i128(&mut self, field: &Field, value: i128) { |
114 | 0 | if field.name() == "__value" { Branch (114:12): [True: 0, False: 0]
Branch (114:12): [Folded - Ignored]
|
115 | 0 | match u64::try_from(value) { |
116 | 0 | Ok(v) => self.value = ValueWithPrimitiveType::U64(v), |
117 | 0 | Err(_) => self.value = ValueWithPrimitiveType::String(value.to_string()), |
118 | | } |
119 | 0 | } |
120 | 0 | } |
121 | 0 | fn record_u128(&mut self, field: &Field, value: u128) { |
122 | 0 | if field.name() == "__value" { Branch (122:12): [True: 0, False: 0]
Branch (122:12): [Folded - Ignored]
|
123 | 0 | match u64::try_from(value) { |
124 | 0 | Ok(v) => self.value = ValueWithPrimitiveType::U64(v), |
125 | 0 | Err(_) => self.value = ValueWithPrimitiveType::String(value.to_string()), |
126 | | } |
127 | 0 | } |
128 | 0 | } |
129 | 0 | fn record_bool(&mut self, field: &Field, value: bool) { |
130 | 0 | if field.name() == "__value" { Branch (130:12): [True: 0, False: 0]
Branch (130:12): [Folded - Ignored]
|
131 | 0 | self.value = ValueWithPrimitiveType::U64(u64::from(value)); |
132 | 0 | } |
133 | 0 | } |
134 | 36 | fn record_str(&mut self, field: &Field, value: &str) { |
135 | 36 | match field.name() { |
136 | 36 | "__value" => self.value = ValueWithPrimitiveType::String(value.to_string())8 , |
137 | 28 | "__help" => self.help = value.to_string()14 , |
138 | 14 | "__name" => self.name = value.to_string(), |
139 | 0 | field => panic!("UNKNOWN FIELD {field}"), |
140 | | } |
141 | 36 | } |
142 | 0 | fn record_error(&mut self, _field: &Field, _value: &(dyn std::error::Error + 'static)) {} |
143 | | } |
144 | | |
145 | | /// An intermediate structed that will have it's contents populated |
146 | | /// by the `tracing` layer for a given field. |
147 | | /// This is the same as `MetricDataVisitor` but only captures info |
148 | | /// about a given span on span creation. |
149 | | pub struct SpanFields { |
150 | | pub name: Cow<'static, str>, |
151 | | } |
152 | | |
153 | | impl Visit for SpanFields { |
154 | 0 | fn record_debug(&mut self, _field: &Field, _value: &dyn Debug) {} |
155 | | |
156 | 4 | fn record_str(&mut self, field: &Field, value: &str) { |
157 | 4 | if field.name() == "__name" { Branch (157:12): [True: 4, False: 0]
Branch (157:12): [Folded - Ignored]
|
158 | 4 | self.name = Cow::Owned(value.to_string()); |
159 | 4 | }0 |
160 | 4 | } |
161 | | } |