micromegas_analytics/
thread_block_processor.rs1use crate::metadata::StreamMetadata;
2use crate::payload::{fetch_block_payload, parse_block};
3use crate::scope::BorrowedScopeDesc;
4use anyhow::{Context, Result};
5use micromegas_telemetry::blob_storage::BlobStorage;
6use micromegas_tracing::prelude::*;
7use micromegas_transit::value::{Object, Value};
8use std::sync::Arc;
9
10pub trait ThreadBlockProcessor {
12 fn on_begin_thread_scope(
14 &mut self,
15 block_id: &str,
16 event_id: i64,
17 scope: BorrowedScopeDesc<'_>,
18 ts: i64,
19 ) -> Result<bool>;
20 fn on_end_thread_scope(
21 &mut self,
22 block_id: &str,
23 event_id: i64,
24 scope: BorrowedScopeDesc<'_>,
25 ts: i64,
26 ) -> Result<bool>;
27}
28
29fn on_thread_event<'a, F>(obj: &Object<'a>, mut fun: F) -> Result<bool>
30where
31 F: FnMut(&'a Object<'a>, i64) -> Result<bool>,
32{
33 let tick = obj.get::<i64>("time")?;
34 let scope = obj.get::<&Object>("thread_span_desc")?;
35 fun(scope, tick)
36}
37
38fn on_thread_named_event<'a, F>(obj: &Object<'a>, mut fun: F) -> Result<bool>
39where
40 F: FnMut(&'a Object<'a>, &'a str, i64) -> Result<bool>,
41{
42 let tick = obj.get::<i64>("time")?;
43 let scope = obj.get::<&Object>("thread_span_location")?;
44 let name = obj.get::<&str>("name")?;
45 fun(scope, name, tick)
46}
47
48#[span_fn]
50pub fn parse_thread_block_payload<Proc: ThreadBlockProcessor>(
51 block_id: &str,
52 object_offset: i64,
53 payload: µmegas_telemetry::block_wire_format::BlockPayload,
54 stream: &StreamMetadata,
55 processor: &mut Proc,
56) -> Result<bool> {
57 let mut event_id = object_offset;
58 parse_block(stream, payload, |val| {
59 let res = if let Value::Object(obj) = val {
60 match obj.type_name {
61 "BeginThreadSpanEvent" => on_thread_event(obj, |scope, ts| {
62 let name = scope.get::<&str>("name")?;
63 let filename = scope.get::<&str>("file")?;
64 let target = scope.get::<&str>("target")?;
65 let line = scope.get::<u32>("line")?;
66 let scope_desc = BorrowedScopeDesc::new(name, filename, target, line);
67 processor.on_begin_thread_scope(block_id, event_id, scope_desc, ts)
68 })
69 .with_context(|| "reading BeginThreadSpanEvent"),
70 "EndThreadSpanEvent" => on_thread_event(obj, |scope, ts| {
71 let name = scope.get::<&str>("name")?;
72 let filename = scope.get::<&str>("file")?;
73 let target = scope.get::<&str>("target")?;
74 let line = scope.get::<u32>("line")?;
75 let scope_desc = BorrowedScopeDesc::new(name, filename, target, line);
76 processor.on_end_thread_scope(block_id, event_id, scope_desc, ts)
77 })
78 .with_context(|| "reading EndThreadSpanEvent"),
79 "BeginThreadNamedSpanEvent" | "BeginThreadDynNamedSpanEvent" => {
80 on_thread_named_event(obj, |scope, name, ts| {
81 let filename = scope.get::<&str>("file")?;
82 let target = scope.get::<&str>("target")?;
83 let line = scope.get::<u32>("line")?;
84 let scope_desc = BorrowedScopeDesc::new(name, filename, target, line);
85 processor.on_begin_thread_scope(block_id, event_id, scope_desc, ts)
86 })
87 .with_context(|| "reading BeginThreadNamedSpanEvent")
88 }
89 "EndThreadNamedSpanEvent" | "EndThreadDynNamedSpanEvent" => {
90 on_thread_named_event(obj, |scope, name, ts| {
91 let filename = scope.get::<&str>("file")?;
92 let target = scope.get::<&str>("target")?;
93 let line = scope.get::<u32>("line")?;
94 let scope_desc = BorrowedScopeDesc::new(name, filename, target, line);
95 processor.on_end_thread_scope(block_id, event_id, scope_desc, ts)
96 })
97 .with_context(|| "reading EndThreadNamedSpanEvent")
98 }
99 "BeginAsyncSpanEvent"
100 | "EndAsyncSpanEvent"
101 | "BeginAsyncNamedSpanEvent"
102 | "EndAsyncNamedSpanEvent"
103 | "BeginAsyncDynNamedSpanEvent"
104 | "EndAsyncDynNamedSpanEvent" => {
105 Ok(true)
107 }
108 event_type => {
109 warn!("unknown event type {}", event_type);
110 Ok(true)
111 }
112 }
113 } else {
114 Ok(true) };
116 event_id += 1;
117 res
118 })
119}
120
121#[span_fn]
123pub async fn parse_thread_block<Proc: ThreadBlockProcessor>(
124 blob_storage: Arc<BlobStorage>,
125 stream: &StreamMetadata,
126 block_id: sqlx::types::Uuid,
127 object_offset: i64,
128 processor: &mut Proc,
129) -> Result<bool> {
130 let payload =
131 fetch_block_payload(blob_storage, stream.process_id, stream.stream_id, block_id).await?;
132 let block_id_str = block_id
133 .hyphenated()
134 .encode_lower(&mut sqlx::types::uuid::Uuid::encode_buffer())
135 .to_owned();
136 info!(
137 "parse_thread_block stream_id={} block_id={block_id_str}",
138 stream.stream_id
139 );
140 parse_thread_block_payload(&block_id_str, object_offset, &payload, stream, processor)
141}