1use crate::{
2 metadata::{ProcessMetadata, StreamMetadata},
3 payload::{fetch_block_payload, parse_block},
4 properties::property_set::PropertySet,
5 time::ConvertTicks,
6};
7use anyhow::{Context, Result};
8use micromegas_telemetry::{blob_storage::BlobStorage, types::block::BlockMetadata};
9use micromegas_tracing::prelude::*;
10use micromegas_transit::value::{Object, Value};
11use std::sync::Arc;
12
13const SECONDS_METRIC_UNIT: &str = "seconds";
15
16pub struct Measure<'a> {
20 pub process: Arc<ProcessMetadata>,
21 pub stream_id: Arc<String>,
22 pub block_id: Arc<String>,
23 pub insert_time: i64, pub time: i64, pub target: &'a str,
26 pub name: &'a str,
27 pub unit: &'a str,
28 pub value: f64,
29 pub properties: PropertySet<'a>,
30}
31
32pub fn measure_from_value<'a>(
34 process: Arc<ProcessMetadata>,
35 stream_id: Arc<String>,
36 block_id: Arc<String>,
37 block_insert_time_ns: i64,
38 convert_ticks: &ConvertTicks,
39 val: Value<'a>,
40) -> Result<Option<Measure<'a>>> {
41 if let Value::Object(obj) = val {
42 match obj.type_name {
43 "FloatMetricEvent" => {
44 let ticks = obj
45 .get::<i64>("time")
46 .with_context(|| "reading time from FloatMetricEvent")?;
47 let value = obj
48 .get::<f64>("value")
49 .with_context(|| "reading value from FloatMetricEvent")?;
50 let desc = obj
51 .get::<&Object>("desc")
52 .with_context(|| "reading desc from FloatMetricEvent")?;
53 let target = desc
54 .get::<&str>("target")
55 .with_context(|| "reading target from FloatMetricEvent")?;
56 let name = desc
57 .get::<&str>("name")
58 .with_context(|| "reading name from FloatMetricEvent")?;
59 let unit = desc
60 .get::<&str>("unit")
61 .with_context(|| "reading unit from FloatMetricEvent")?;
62 Ok(Some(Measure {
63 process,
64 stream_id,
65 block_id,
66 insert_time: block_insert_time_ns,
67 time: convert_ticks.ticks_to_nanoseconds(ticks),
68 target,
69 name,
70 unit,
71 value,
72 properties: PropertySet::empty(),
73 }))
74 }
75 "IntegerMetricEvent" => {
76 let ticks = obj
77 .get::<i64>("time")
78 .with_context(|| "reading time from IntegerMetricEvent")?;
79 let time = convert_ticks.ticks_to_nanoseconds(ticks);
80 let value = obj
81 .get::<u64>("value")
82 .with_context(|| "reading value from IntegerMetricEvent")?;
83 let desc = obj
84 .get::<&Object>("desc")
85 .with_context(|| "reading desc from IntegerMetricEvent")?;
86 let target = desc
87 .get::<&str>("target")
88 .with_context(|| "reading target from IntegerMetricEvent")?;
89 let name = desc
90 .get::<&str>("name")
91 .with_context(|| "reading name from IntegerMetricEvent")?;
92 let unit = desc
93 .get::<&str>("unit")
94 .with_context(|| "reading unit from IntegerMetricEvent")?;
95 if unit == "ticks" {
96 Ok(Some(Measure {
97 process,
98 stream_id,
99 block_id,
100 insert_time: block_insert_time_ns,
101 time,
102 target,
103 name,
104 unit: SECONDS_METRIC_UNIT,
105 value: convert_ticks.delta_ticks_to_ms(value as i64) / 1000.0,
106 properties: PropertySet::empty(),
107 }))
108 } else {
109 Ok(Some(Measure {
110 process,
111 stream_id,
112 block_id,
113 insert_time: block_insert_time_ns,
114 time,
115 target,
116 name,
117 unit,
118 value: value as f64,
119 properties: PropertySet::empty(),
120 }))
121 }
122 }
123 "TaggedIntegerMetricEvent" => {
124 let ticks = obj
125 .get::<i64>("time")
126 .with_context(|| "reading time from TaggedIntegerMetricEvent")?;
127 let time = convert_ticks.ticks_to_nanoseconds(ticks);
128 let value = obj
129 .get::<u64>("value")
130 .with_context(|| "reading value from TaggedIntegerMetricEvent")?;
131 let desc = obj
132 .get::<&Object>("desc")
133 .with_context(|| "reading desc from IntegerMetricEvent")?;
134 let mut target = desc
135 .get::<&str>("target")
136 .with_context(|| "reading target from IntegerMetricEvent")?;
137 let mut name = desc
138 .get::<&str>("name")
139 .with_context(|| "reading name from IntegerMetricEvent")?;
140 let mut unit = desc
141 .get::<&str>("unit")
142 .with_context(|| "reading unit from IntegerMetricEvent")?;
143 let properties = obj
144 .get::<&Object>("properties")
145 .with_context(|| "reading properties from TaggedIntegerMetricEvent")?;
146 for &(prop_name, prop_value) in properties.members {
147 match (prop_name, prop_value) {
148 ("target", Value::String(value_str)) => {
149 target = value_str;
150 }
151 ("name", Value::String(value_str)) => {
152 name = value_str;
153 }
154 ("unit", Value::String(value_str)) => {
155 unit = value_str;
156 }
157 (_, _) => {}
158 }
159 }
160
161 if unit == "ticks" {
162 Ok(Some(Measure {
163 process,
164 stream_id,
165 block_id,
166 insert_time: block_insert_time_ns,
167 time,
168 target,
169 name,
170 unit: SECONDS_METRIC_UNIT,
171 value: convert_ticks.delta_ticks_to_ms(value as i64) / 1000.0,
172 properties: properties.into(),
173 }))
174 } else {
175 Ok(Some(Measure {
176 process,
177 stream_id,
178 block_id,
179 insert_time: block_insert_time_ns,
180 time,
181 target,
182 name,
183 unit,
184 value: value as f64,
185 properties: properties.into(),
186 }))
187 }
188 }
189 "TaggedFloatMetricEvent" => {
190 let ticks = obj
191 .get::<i64>("time")
192 .with_context(|| "reading time from TaggedFloatMetricEvent")?;
193 let time = convert_ticks.ticks_to_nanoseconds(ticks);
194 let value = obj
195 .get::<f64>("value")
196 .with_context(|| "reading value from TaggedFloatMetricEvent")?;
197 let desc = obj
198 .get::<&Object>("desc")
199 .with_context(|| "reading desc from TaggedFloatMetricEvent")?;
200 let mut target = desc
201 .get::<&str>("target")
202 .with_context(|| "reading target from TaggedFloatMetricEvent")?;
203 let mut name = desc
204 .get::<&str>("name")
205 .with_context(|| "reading name from TaggedFloatMetricEvent")?;
206 let mut unit = desc
207 .get::<&str>("unit")
208 .with_context(|| "reading unit from TaggedFloatMetricEvent")?;
209 let properties = obj
210 .get::<&Object>("properties")
211 .with_context(|| "reading properties from TaggedFloatMetricEvent")?;
212 for &(prop_name, prop_value) in properties.members {
213 match (prop_name, prop_value) {
214 ("target", Value::String(value_str)) => {
215 target = value_str;
216 }
217 ("name", Value::String(value_str)) => {
218 name = value_str;
219 }
220 ("unit", Value::String(value_str)) => {
221 unit = value_str;
222 }
223 (_, _) => {}
224 }
225 }
226 Ok(Some(Measure {
227 process,
228 stream_id,
229 block_id,
230 insert_time: block_insert_time_ns,
231 time,
232 target,
233 name,
234 unit,
235 value,
236 properties: properties.into(),
237 }))
238 }
239
240 _ => {
241 warn!("unknown metric event {:?}", obj);
242 Ok(None)
243 }
244 }
245 } else {
246 Ok(None)
247 }
248}
249
250#[span_fn]
252pub async fn for_each_measure_in_block<Predicate>(
253 blob_storage: Arc<BlobStorage>,
254 convert_ticks: &ConvertTicks,
255 process: Arc<ProcessMetadata>,
256 stream: &StreamMetadata,
257 block: &BlockMetadata,
258 mut fun: Predicate,
259) -> Result<bool>
260where
261 Predicate: for<'a> FnMut(Measure<'a>) -> Result<bool>,
262{
263 let payload = fetch_block_payload(
264 blob_storage,
265 stream.process_id,
266 stream.stream_id,
267 block.block_id,
268 )
269 .await?;
270 let stream_id = Arc::new(stream.stream_id.to_string());
271 let block_id = Arc::new(block.block_id.to_string());
272 let block_insert_time_ns = block.insert_time.timestamp_nanos_opt().unwrap_or_default();
273 let continue_iterating = parse_block(stream, &payload, |val| {
274 if let Some(measure) = measure_from_value(
275 process.clone(),
276 stream_id.clone(),
277 block_id.clone(),
278 block_insert_time_ns,
279 convert_ticks,
280 val,
281 )
282 .with_context(|| "measure_from_value")?
283 && !fun(measure)?
284 {
285 return Ok(false); }
287 Ok(true) })
289 .with_context(|| format!("parse_block {}", block.block_id))?;
290 Ok(continue_iterating)
291}