bpf_loader_lib/export_event/
mod.rs1use crate::{
36 btf_container::BtfContainer,
37 export_event::checker::check_sample_types_btf,
38 meta::{BufferValueInterpreter, ExportedTypesStructMeta, MapSampleMeta, SampleMapType},
39};
40use anyhow::{anyhow, bail, Context, Result};
41use log::debug;
42use std::{any::Any, fmt::Display, sync::Arc};
43
44use self::{
45 checker::check_export_types_btf,
46 event_handlers::{buffer, get_plain_text_checked_types_header, sample_map},
47 type_descriptor::{CheckedExportedMember, TypeDescriptor},
48};
49
50pub(crate) mod checker;
51pub(crate) mod data_dumper;
52pub(crate) mod event_handlers;
53#[cfg(test)]
54mod tests;
55pub mod type_descriptor;
57#[derive(Clone, Copy)]
58pub enum ExportFormatType {
60 PlainText,
62 Json,
64 RawEvent,
66}
67#[derive(Debug)]
68pub enum ReceivedEventData<'a> {
70 Buffer(&'a [u8]),
72 KeyValueBuffer {
74 key: &'a [u8],
75 value: &'a [u8],
76 },
77 PlainText(&'a str),
79 JsonText(&'a str),
81}
82impl<'a> Display for ReceivedEventData<'a> {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 match self {
85 ReceivedEventData::Buffer(b) => {
86 write!(f, "{b:?}")?;
87 }
88 ReceivedEventData::KeyValueBuffer { key, value } => {
89 write!(f, "key: {key:?} value: {value:?}")?;
90 }
91 ReceivedEventData::PlainText(s) | ReceivedEventData::JsonText(s) => {
92 write!(f, "{s}")?;
93 }
94 }
95 Ok(())
96 }
97}
98
99impl<'a> ReceivedEventData<'a> {
100 pub fn trivally_to_plain_bytes(&self) -> &'a [u8] {
102 match self {
103 ReceivedEventData::Buffer(buf) => buf,
104 ReceivedEventData::KeyValueBuffer { value, .. } => value,
105 ReceivedEventData::PlainText(txt) => txt.as_bytes(),
106 ReceivedEventData::JsonText(txt) => txt.as_bytes(),
107 }
108 }
109}
110
111pub trait EventHandler {
113 fn handle_event(&self, context: Option<Arc<dyn Any>>, data: ReceivedEventData);
114}
115
116pub(crate) enum ExporterInternalImplementation {
117 BufferValueProcessor {
118 event_processor: Box<dyn InternalBufferValueEventProcessor>,
120 checked_types: Vec<CheckedExportedMember>,
122 },
123 KeyValueMapProcessor {
124 event_processor: Box<dyn InternalSampleMapProcessor>,
126 checked_key_types: Vec<CheckedExportedMember>,
128 checked_value_types: Vec<CheckedExportedMember>,
130 sample_map_config: MapSampleMeta,
132 },
133}
134
135pub struct EventExporter {
137 pub(crate) user_export_event_handler: Option<Arc<dyn EventHandler>>,
139 pub(crate) internal_impl: ExporterInternalImplementation,
140 pub(crate) user_ctx: Option<Arc<dyn Any>>,
142 pub(crate) btf_container: Arc<BtfContainer>,
143}
144
145impl EventExporter {
146 pub(crate) fn dump_data_to_user_callback_or_stdout(&self, data: ReceivedEventData) {
147 dump_data_to_user_callback_or_stdout(
148 self.user_export_event_handler.clone(),
149 self.user_ctx.clone(),
150 data,
151 );
152 }
153}
154pub(crate) fn dump_data_to_user_callback_or_stdout(
155 user_export_event_handler: Option<Arc<dyn EventHandler>>,
156 user_ctx: Option<Arc<dyn Any>>,
157 data: ReceivedEventData,
158) {
159 if let Some(callback) = user_export_event_handler.as_ref() {
160 callback.handle_event(user_ctx, data);
161 } else {
162 println!("{data}");
163 }
164}
165pub(crate) trait InternalBufferValueEventProcessor {
166 fn handle_event(&self, data: &[u8]) -> Result<()>;
167}
168
169pub(crate) trait InternalSampleMapProcessor {
170 fn handle_event(&self, key_buffer: &[u8], value_buffer: &[u8]) -> Result<()>;
171}
172
173pub struct EventExporterBuilder {
175 export_format: ExportFormatType,
176 export_event_handler: Option<Arc<dyn EventHandler>>,
177 user_ctx: Option<Arc<dyn Any>>,
178}
179
180impl Default for EventExporterBuilder {
181 fn default() -> Self {
182 Self {
183 export_format: ExportFormatType::PlainText,
184 export_event_handler: None,
185 user_ctx: None,
186 }
187 }
188}
189
190impl EventExporterBuilder {
191 pub fn new() -> Self {
193 Self::default()
194 }
195 pub fn set_export_format(self, fmt: ExportFormatType) -> Self {
197 Self {
198 export_format: fmt,
199 ..self
200 }
201 }
202 pub fn set_export_event_handler(self, handler: Arc<dyn EventHandler>) -> Self {
204 Self {
205 export_event_handler: Some(handler),
206 ..self
207 }
208 }
209 pub fn set_user_context<T: Any>(self, ctx: T) -> Self {
211 Self {
212 user_ctx: Some(Arc::new(ctx)),
213 ..self
214 }
215 }
216 pub fn build_for_single_value_with_type_descriptor(
218 self,
219 export_type: TypeDescriptor,
220 btf_container: Arc<BtfContainer>,
221 intepreter: &BufferValueInterpreter,
222 ) -> Result<Arc<EventExporter>> {
223 let mut checked_exported_members =
224 export_type.build_checked_exported_members(btf_container.borrow_btf())?;
225 if matches!(intepreter, BufferValueInterpreter::StackTrace { .. })
226 && !matches!(self.export_format, ExportFormatType::PlainText)
227 {
228 bail!("Intepreter `stack_trace` could only be paired with plaintext export format");
229 }
230 Ok(Arc::new_cyclic(move |me| {
231 let internal_event_processor: Box<dyn InternalBufferValueEventProcessor> =
232 match (self.export_format, intepreter) {
233 (ExportFormatType::Json, BufferValueInterpreter::DefaultStruct) => {
234 Box::new(buffer::JsonExportEventHandler {
235 exporter: me.clone(),
236 })
237 }
238 (
239 ExportFormatType::PlainText,
240 BufferValueInterpreter::StackTrace {
241 field_map,
242 with_symbols,
243 },
244 ) => {
245 debug!("Using stack trace exporter");
246 Box::new(buffer::PlainTextStackTraceExportEventHandler {
247 exporter: me.clone(),
248 field_mapping: field_map.clone(),
249 with_symbols: *with_symbols,
250 })
251 }
252 (ExportFormatType::PlainText, BufferValueInterpreter::DefaultStruct) => {
253 let header = get_plain_text_checked_types_header(
254 &mut checked_exported_members,
255 "TIME ",
256 );
257 dump_data_to_user_callback_or_stdout(
258 self.export_event_handler.clone(),
259 self.user_ctx.clone(),
260 ReceivedEventData::PlainText(header.as_str()),
261 );
262 Box::new(buffer::PlainStringExportEventHandler {
263 exporter: me.clone(),
264 })
265 }
266
267 (ExportFormatType::RawEvent, BufferValueInterpreter::DefaultStruct) => {
268 Box::new(buffer::RawExportEventHandler {
269 exporter: me.clone(),
270 })
271 }
272 (_, _) => unreachable!("Unexpected exportformattype + intepreter"),
273 };
274 EventExporter {
275 user_export_event_handler: self.export_event_handler,
276 user_ctx: self.user_ctx,
277 btf_container,
278 internal_impl: ExporterInternalImplementation::BufferValueProcessor {
279 event_processor: internal_event_processor,
280 checked_types: checked_exported_members,
281 },
282 }
283 }))
284 }
285 pub fn build_for_single_value(
289 self,
290 export_type: &ExportedTypesStructMeta,
291 btf_container: Arc<BtfContainer>,
292 intepreter: &BufferValueInterpreter,
293 ) -> Result<Arc<EventExporter>> {
294 let checked_members = check_export_types_btf(export_type, btf_container.borrow_btf())?;
295 Self::build_for_single_value_with_type_descriptor(
296 self,
297 TypeDescriptor::CheckedMembers(checked_members),
298 btf_container,
299 intepreter,
300 )
301 }
302 pub fn build_for_key_value_with_type_desc(
304 self,
305 key_export_type: TypeDescriptor,
306 value_export_type: TypeDescriptor,
307 sample_config: &MapSampleMeta,
308 btf_container: Arc<BtfContainer>,
309 ) -> Result<Arc<EventExporter>> {
310 let mut checked_key_types =
311 key_export_type.build_checked_exported_members(btf_container.borrow_btf())?;
312 let mut checked_value_types =
313 value_export_type.build_checked_exported_members(btf_container.borrow_btf())?;
314
315 if matches!(self.export_format, ExportFormatType::PlainText)
316 && matches!(sample_config.ty, SampleMapType::LinearHist)
317 {
318 bail!("Linear hist sampling is not supported now");
319 }
320 Ok(Arc::new_cyclic(move |me| {
321 let internal_sample_map_processor: Box<dyn InternalSampleMapProcessor> = match self
322 .export_format
323 {
324 ExportFormatType::PlainText => match sample_config.ty {
325 SampleMapType::Log2Hist => Box::new(sample_map::Log2HistExportEventHandler {
326 exporter: me.clone(),
327 }),
328 SampleMapType::DefaultKV => {
329 let header = String::from("TIME ");
330 let header =
331 get_plain_text_checked_types_header(&mut checked_key_types, header);
332 let header =
333 get_plain_text_checked_types_header(&mut checked_value_types, header);
334 dump_data_to_user_callback_or_stdout(
335 self.export_event_handler.clone(),
336 self.user_ctx.clone(),
337 ReceivedEventData::PlainText(header.as_str()),
338 );
339 Box::new(sample_map::DefaultKVStringExportEventHandler {
340 exporter: me.clone(),
341 })
342 }
343 SampleMapType::LinearHist => unreachable!(),
344 },
345 ExportFormatType::Json => Box::new(sample_map::JsonExportEventHandler {
346 exporter: me.clone(),
347 }),
348 ExportFormatType::RawEvent => Box::new(sample_map::RawExportEventHandler {
349 exporter: me.clone(),
350 }),
351 };
352 EventExporter {
353 user_export_event_handler: self.export_event_handler,
354 internal_impl: ExporterInternalImplementation::KeyValueMapProcessor {
355 event_processor: internal_sample_map_processor,
356 checked_key_types,
357 checked_value_types,
358 sample_map_config: sample_config.clone(),
359 },
360 user_ctx: self.user_ctx,
361 btf_container,
362 }
363 }))
364 }
365 pub fn build_for_key_value(
372 self,
373 key_type_id: u32,
374 value_type_id: u32,
375 sample_config: &MapSampleMeta,
376 export_type: &ExportedTypesStructMeta,
377 btf_container: Arc<BtfContainer>,
378 ) -> Result<Arc<EventExporter>> {
379 let btf = btf_container.borrow_btf();
380 let checked_key_types = check_sample_types_btf(btf, key_type_id, None)
381 .with_context(|| anyhow!("Failed to check key type"))?;
382 let checked_value_types =
383 check_sample_types_btf(btf, value_type_id, Some(export_type.clone()))
384 .with_context(|| anyhow!("Failed to check value type"))?;
385 self.build_for_key_value_with_type_desc(
386 TypeDescriptor::CheckedMembers(checked_key_types),
387 TypeDescriptor::CheckedMembers(checked_value_types),
388 sample_config,
389 btf_container,
390 )
391 }
392}