1pub use crate::errors::{Error, Result};
3use crate::images::{ImageBlock, ImageEvent, ImageStream};
4use crate::intern_string::intern_string;
5use crate::logs::TaggedLogString;
6use crate::metrics::{TaggedFloatMetricEvent, TaggedIntegerMetricEvent};
7use crate::prelude::*;
8use crate::property_set::PropertySet;
9use crate::{
10 event::{EventSink, NullEventSink, TracingBlock},
11 info,
12 logs::{
13 LogBlock, LogMetadata, LogStaticStrEvent, LogStaticStrInteropEvent, LogStream,
14 LogStringEvent, LogStringInteropEvent,
15 },
16 metrics::{
17 FloatMetricEvent, IntegerMetricEvent, MetricsBlock, MetricsStream, StaticMetricMetadata,
18 },
19 spans::{
20 BeginAsyncNamedSpanEvent, BeginAsyncSpanEvent, BeginThreadNamedSpanEvent,
21 BeginThreadSpanEvent, EndAsyncNamedSpanEvent, EndAsyncSpanEvent, EndThreadNamedSpanEvent,
22 EndThreadSpanEvent, SpanLocation, SpanMetadata, ThreadBlock, ThreadEventQueueTypeIndex,
23 ThreadStream,
24 },
25 warn,
26};
27
28const IMAGE_BUFFER_SIZE: usize = 1024 * 1024;
29use chrono::Utc;
30use std::cell::OnceCell;
31use std::cell::UnsafeCell;
32use std::collections::HashMap;
33use std::fmt;
34use std::sync::RwLock;
35use std::{
36 cell::Cell,
37 sync::{Arc, Mutex},
38};
39
40pub fn init_event_dispatch(
41 logs_buffer_size: usize,
42 metrics_buffer_size: usize,
43 threads_buffer_size: usize,
44 sink: Arc<dyn EventSink>,
45 process_properties: HashMap<String, String>,
46 cpu_tracing_enabled: bool,
47) -> Result<()> {
48 lazy_static::lazy_static! {
49 static ref INIT_MUTEX: Mutex<()> = Mutex::new(());
50 }
51 let _guard = INIT_MUTEX.lock().unwrap();
52 let dispatch_ref = &G_DISPATCH.inner;
53 unsafe {
54 if (*dispatch_ref.get()).get().is_none() {
55 (*dispatch_ref.get())
56 .set(Dispatch::new(
57 logs_buffer_size,
58 metrics_buffer_size,
59 threads_buffer_size,
60 sink,
61 process_properties,
62 cpu_tracing_enabled,
63 ))
64 .map_err(|_| Error::AlreadyInitialized())
65 } else {
66 info!("event dispatch already initialized");
67 Err(Error::AlreadyInitialized())
68 }
69 }
70}
71
72#[inline]
73pub fn process_id() -> Option<uuid::Uuid> {
74 G_DISPATCH.get().map(Dispatch::get_process_id)
75}
76
77#[inline]
78pub fn cpu_tracing_enabled() -> Option<bool> {
79 G_DISPATCH.get().map(Dispatch::get_cpu_tracing_enabled)
80}
81
82pub fn get_sink() -> Option<Arc<dyn EventSink>> {
83 G_DISPATCH.get().map(Dispatch::get_sink)
84}
85
86pub fn shutdown_dispatch() {
87 G_DISPATCH.get().map(Dispatch::shutdown);
88}
89
90#[inline(always)]
91pub fn int_metric(metric_desc: &'static StaticMetricMetadata, value: u64) {
92 if let Some(d) = G_DISPATCH.get() {
93 d.int_metric(metric_desc, value);
94 }
95}
96
97#[inline(always)]
98pub fn float_metric(metric_desc: &'static StaticMetricMetadata, value: f64) {
99 if let Some(d) = G_DISPATCH.get() {
100 d.float_metric(metric_desc, value);
101 }
102}
103
104#[inline(always)]
105pub fn tagged_float_metric(
106 desc: &'static StaticMetricMetadata,
107 properties: &'static PropertySet,
108 value: f64,
109) {
110 if let Some(d) = G_DISPATCH.get() {
111 d.tagged_float_metric(desc, properties, value);
112 }
113}
114
115#[inline(always)]
116pub fn tagged_integer_metric(
117 desc: &'static StaticMetricMetadata,
118 properties: &'static PropertySet,
119 value: u64,
120) {
121 if let Some(d) = G_DISPATCH.get() {
122 d.tagged_integer_metric(desc, properties, value);
123 }
124}
125
126#[inline(always)]
127pub fn log(desc: &'static LogMetadata, args: fmt::Arguments<'_>) {
128 if let Some(d) = G_DISPATCH.get() {
129 d.log(desc, args);
130 }
131}
132
133#[inline(always)]
134pub fn log_tagged(
135 desc: &'static LogMetadata,
136 properties: &'static PropertySet,
137 args: fmt::Arguments<'_>,
138) {
139 if let Some(d) = G_DISPATCH.get() {
140 d.log_tagged(desc, properties, args);
141 }
142}
143
144#[inline(always)]
145pub fn log_interop(metadata: &LogMetadata, args: fmt::Arguments<'_>) {
146 if let Some(d) = G_DISPATCH.get() {
147 d.log_interop(metadata, args);
148 }
149}
150
151#[inline(always)]
152pub fn log_enabled(metadata: &LogMetadata) -> bool {
153 if let Some(d) = G_DISPATCH.get() {
154 d.log_enabled(metadata)
155 } else {
156 false
157 }
158}
159
160#[inline(always)]
161pub fn flush_log_buffer() {
162 if let Some(d) = G_DISPATCH.get() {
163 d.flush_log_buffer();
164 }
165}
166
167pub fn send_image(name: &str, format: &str, data: Vec<u8>) {
168 if let Some(d) = G_DISPATCH.get() {
169 d.send_image(name, format, data);
170 }
171}
172
173#[inline(always)]
174pub fn flush_image_buffer() {
175 if let Some(d) = G_DISPATCH.get() {
176 d.flush_image_buffer();
177 }
178}
179
180#[inline(always)]
181pub fn flush_metrics_buffer() {
182 if let Some(d) = G_DISPATCH.get() {
183 d.flush_metrics_buffer();
184 }
185}
186
187#[inline(always)]
190pub fn init_thread_stream() {
191 LOCAL_THREAD_STREAM.with(|cell| unsafe {
192 if (*cell.as_ptr()).is_some() {
193 return;
194 }
195 #[allow(static_mut_refs)]
196 if let Some(d) = G_DISPATCH.get() {
197 if !d.cpu_tracing_enabled {
199 return;
200 }
201 d.init_thread_stream(cell);
202 } else {
203 warn!("dispatch not initialized, cannot init thread stream, events will be lost for this thread");
204 }
205 });
206}
207
208pub fn for_each_thread_stream(fun: &mut dyn FnMut(*mut ThreadStream)) {
209 if let Some(d) = G_DISPATCH.get() {
210 d.for_each_thread_stream(fun);
211 }
212}
213
214#[inline(always)]
215pub fn flush_thread_buffer() {
216 LOCAL_THREAD_STREAM.with(|cell| unsafe {
217 let opt_stream = &mut *cell.as_ptr();
218 if let Some(stream) = opt_stream {
219 #[allow(static_mut_refs)]
220 match G_DISPATCH.get() {
221 Some(d) => {
222 d.flush_thread_buffer(stream);
223 }
224 None => {
225 panic!("threads are recording but there is no event dispatch");
226 }
227 }
228 }
229 });
230}
231
232#[inline(always)]
235pub fn unregister_thread_stream() {
236 LOCAL_THREAD_STREAM.with(|cell| unsafe {
237 let opt_stream = &mut *cell.as_ptr();
238 if let Some(stream) = opt_stream {
239 #[allow(static_mut_refs)]
240 match G_DISPATCH.get() {
241 Some(d) => {
242 d.flush_thread_buffer(stream);
244 d.unregister_thread_stream(stream);
246 *opt_stream = None;
248 }
249 None => {
250 *opt_stream = None;
252 }
253 }
254 }
255 });
256}
257
258#[inline(always)]
259pub fn on_begin_scope(scope: &'static SpanMetadata) {
260 on_thread_event(BeginThreadSpanEvent {
261 time: now(),
262 thread_span_desc: scope,
263 });
264}
265
266#[inline(always)]
267pub fn on_end_scope(scope: &'static SpanMetadata) {
268 on_thread_event(EndThreadSpanEvent {
269 time: now(),
270 thread_span_desc: scope,
271 });
272}
273
274#[inline(always)]
275pub fn on_begin_named_scope(thread_span_location: &'static SpanLocation, name: &'static str) {
276 on_thread_event(BeginThreadNamedSpanEvent {
277 thread_span_location,
278 name: name.into(),
279 time: now(),
280 });
281}
282
283#[inline(always)]
284pub fn on_end_named_scope(thread_span_location: &'static SpanLocation, name: &'static str) {
285 on_thread_event(EndThreadNamedSpanEvent {
286 thread_span_location,
287 name: name.into(),
288 time: now(),
289 });
290}
291
292#[inline(always)]
293pub fn on_begin_async_scope(scope: &'static SpanMetadata, parent_span_id: u64, depth: u32) -> u64 {
294 let id = G_ASYNC_SPAN_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
295 on_thread_event(BeginAsyncSpanEvent {
296 span_desc: scope,
297 span_id: id as u64,
298 parent_span_id,
299 depth,
300 time: now(),
301 });
302 id as u64
303}
304
305#[inline(always)]
306pub fn on_end_async_scope(
307 span_id: u64,
308 parent_span_id: u64,
309 scope: &'static SpanMetadata,
310 depth: u32,
311) {
312 on_thread_event(EndAsyncSpanEvent {
313 span_desc: scope,
314 span_id,
315 parent_span_id,
316 depth,
317 time: now(),
318 });
319}
320
321#[inline(always)]
322pub fn on_begin_async_named_scope(
323 span_location: &'static SpanLocation,
324 name: &'static str,
325 parent_span_id: u64,
326 depth: u32,
327) -> u64 {
328 let id = G_ASYNC_SPAN_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
329 on_thread_event(BeginAsyncNamedSpanEvent {
330 span_location,
331 name: name.into(),
332 span_id: id as u64,
333 parent_span_id,
334 depth,
335 time: now(),
336 });
337 id as u64
338}
339
340#[inline(always)]
341pub fn on_end_async_named_scope(
342 span_id: u64,
343 parent_span_id: u64,
344 span_location: &'static SpanLocation,
345 name: &'static str,
346 depth: u32,
347) {
348 on_thread_event(EndAsyncNamedSpanEvent {
349 span_location,
350 name: name.into(),
351 span_id,
352 parent_span_id,
353 depth,
354 time: now(),
355 });
356}
357
358pub struct DispatchCell {
359 inner: UnsafeCell<OnceCell<Dispatch>>,
361}
362
363impl DispatchCell {
364 const fn new() -> Self {
365 Self {
366 inner: UnsafeCell::new(OnceCell::new()),
367 }
368 }
369
370 fn get(&self) -> Option<&Dispatch> {
371 unsafe { (*self.inner.get()).get() }
372 }
373
374 unsafe fn take(&self) -> Option<Dispatch> {
375 unsafe { (*self.inner.get()).take() }
376 }
377}
378
379unsafe impl Sync for DispatchCell {}
381
382static G_DISPATCH: DispatchCell = DispatchCell::new();
383static G_ASYNC_SPAN_COUNTER: std::sync::atomic::AtomicUsize =
384 std::sync::atomic::AtomicUsize::new(1);
385
386pub unsafe fn force_uninit() {
390 unsafe {
391 G_DISPATCH.take();
392 }
393}
394
395thread_local! {
396 static LOCAL_THREAD_STREAM: Cell<Option<ThreadStream>> = const { Cell::new(None) };
397}
398
399#[inline(always)]
400fn on_thread_event<T>(event: T)
401where
402 T: micromegas_transit::InProcSerialize + ThreadEventQueueTypeIndex,
403{
404 LOCAL_THREAD_STREAM.with(|cell| unsafe {
405 let opt_stream = &mut *cell.as_ptr();
406 if let Some(stream) = opt_stream {
407 stream.get_events_mut().push(event);
408 if stream.is_full() {
409 flush_thread_buffer();
410 }
411 }
412 });
413}
414
415struct Dispatch {
416 process_id: uuid::Uuid,
417 logs_buffer_size: usize,
418 metrics_buffer_size: usize,
419 threads_buffer_size: usize,
420 cpu_tracing_enabled: bool,
421 image_stream: Mutex<ImageStream>,
422 log_stream: Mutex<LogStream>,
423 metrics_stream: Mutex<MetricsStream>,
424 thread_streams: Mutex<Vec<*mut ThreadStream>>, sink: RwLock<Arc<dyn EventSink>>,
426}
427
428impl Dispatch {
429 pub fn new(
430 logs_buffer_size: usize,
431 metrics_buffer_size: usize,
432 threads_buffer_size: usize,
433 sink: Arc<dyn EventSink>,
434 process_properties: HashMap<String, String>,
435 cpu_tracing_enabled: bool,
436 ) -> Self {
437 let process_id = uuid::Uuid::new_v4();
438 let obj = Self {
439 process_id,
440 logs_buffer_size,
441 metrics_buffer_size,
442 threads_buffer_size,
443 cpu_tracing_enabled,
444 image_stream: Mutex::new(ImageStream::new(
445 IMAGE_BUFFER_SIZE,
446 process_id,
447 &[String::from("image")],
448 HashMap::new(),
449 )),
450 log_stream: Mutex::new(LogStream::new(
451 logs_buffer_size,
452 process_id,
453 &[String::from("log")],
454 HashMap::new(),
455 )),
456 metrics_stream: Mutex::new(MetricsStream::new(
457 metrics_buffer_size,
458 process_id,
459 &[String::from("metrics")],
460 HashMap::new(),
461 )),
462 thread_streams: Mutex::new(vec![]),
463 sink: RwLock::new(sink),
464 };
465 obj.startup(process_properties);
466 obj.init_image_stream();
467 obj.init_log_stream();
468 obj.init_metrics_stream();
469 obj
470 }
471
472 pub fn get_process_id(&self) -> uuid::Uuid {
473 self.process_id
474 }
475
476 pub fn get_cpu_tracing_enabled(&self) -> bool {
477 self.cpu_tracing_enabled
478 }
479
480 pub fn get_sink(&self) -> Arc<dyn EventSink> {
481 if let Ok(guard) = self.sink.try_read() {
482 (*guard).clone()
483 } else {
484 Arc::new(NullEventSink {})
485 }
486 }
487
488 fn shutdown(&self) {
489 let old_sink = self.get_sink();
490 let null_sink = Arc::new(NullEventSink {});
491 if let Ok(mut guard) = self.sink.write() {
492 *guard = null_sink;
493 drop(guard)
494 }
495 old_sink.on_shutdown();
496 }
497
498 fn startup(&self, process_properties: HashMap<String, String>) {
499 let mut parent_process = None;
500
501 if let Ok(parent_process_guid) = std::env::var("MICROMEGAS_TELEMETRY_PARENT_PROCESS")
502 && let Ok(parent_process_id) = uuid::Uuid::try_parse(&parent_process_guid)
503 {
504 parent_process = Some(parent_process_id);
505 }
506
507 unsafe {
508 std::env::set_var(
509 "MICROMEGAS_TELEMETRY_PARENT_PROCESS",
510 self.process_id.to_string(),
511 );
512 }
513
514 let process_info = Arc::new(make_process_info(
515 self.process_id,
516 parent_process,
517 process_properties,
518 ));
519
520 self.get_sink().on_startup(process_info);
521 }
522
523 fn init_log_stream(&self) {
524 let log_stream = self.log_stream.lock().unwrap();
525 self.get_sink().on_init_log_stream(&log_stream);
526 }
527
528 fn init_image_stream(&self) {
529 let image_stream = self.image_stream.lock().expect("image_stream lock");
530 self.get_sink().on_init_image_stream(&image_stream);
531 }
532
533 fn init_metrics_stream(&self) {
534 let metrics_stream = self.metrics_stream.lock().unwrap();
535 self.get_sink().on_init_metrics_stream(&metrics_stream);
536 }
537
538 pub fn send_image(&self, name: &str, format: &str, data: Vec<u8>) {
539 let time = now();
540 let mut image_stream = self.image_stream.lock().expect("image_stream lock");
541 image_stream.get_events_mut().push(ImageEvent {
542 time,
543 name: micromegas_transit::DynString(name.to_owned()),
544 format: micromegas_transit::DynString(format.to_owned()),
545 data: micromegas_transit::DynBlob(data),
546 });
547 if image_stream.is_full() {
548 drop(image_stream);
549 self.flush_image_buffer();
550 }
551 }
552
553 fn flush_image_buffer(&self) {
554 let mut image_stream = self.image_stream.lock().expect("image_stream lock");
555 if image_stream.is_empty() {
556 return;
557 }
558 let stream_id = image_stream.stream_id();
559 let next_offset = image_stream.get_block_ref().object_offset()
560 + image_stream.get_block_ref().nb_objects();
561 let mut old_event_block = image_stream.replace_block(Arc::new(ImageBlock::new(
562 IMAGE_BUFFER_SIZE,
563 self.process_id,
564 stream_id,
565 next_offset,
566 )));
567 assert!(!image_stream.is_full());
568 Arc::get_mut(&mut old_event_block)
569 .expect("image block exclusive ref")
570 .close();
571 drop(image_stream);
572 self.get_sink().on_process_image_block(old_event_block);
573 }
574
575 fn init_thread_stream(&self, cell: &Cell<Option<ThreadStream>>) {
576 if !self.cpu_tracing_enabled {
578 return;
579 }
580
581 let mut properties = HashMap::new();
582 properties.insert(String::from("thread-id"), thread_id::get().to_string());
583 if let Some(name) = std::thread::current().name() {
584 properties.insert("thread-name".to_owned(), name.to_owned());
585 }
586 let thread_stream = ThreadStream::new(
587 self.threads_buffer_size,
588 self.process_id,
589 &["cpu".to_owned()],
590 properties,
591 );
592 unsafe {
593 let opt_ref = &mut *cell.as_ptr();
594 self.get_sink().on_init_thread_stream(&thread_stream);
595 *opt_ref = Some(thread_stream);
596 let mut vec_guard = self.thread_streams.lock().unwrap();
597 vec_guard.push(opt_ref.as_mut().unwrap());
598 }
599 }
600
601 fn for_each_thread_stream(&self, fun: &mut dyn FnMut(*mut ThreadStream)) {
602 let mut vec_guard = self.thread_streams.lock().unwrap();
603 for stream in &mut *vec_guard {
604 fun(*stream);
605 }
606 }
607
608 fn unregister_thread_stream(&self, stream_to_remove: &mut ThreadStream) {
609 let mut vec_guard = self.thread_streams.lock().unwrap();
610 let stream_ptr = stream_to_remove as *mut ThreadStream;
611
612 if let Some(pos) = vec_guard.iter().position(|&ptr| ptr == stream_ptr) {
614 vec_guard.remove(pos);
615 }
616 }
617
618 #[inline]
619 fn int_metric(&self, desc: &'static StaticMetricMetadata, value: u64) {
620 let time = now();
621 let mut metrics_stream = self.metrics_stream.lock().unwrap();
622 metrics_stream
623 .get_events_mut()
624 .push(IntegerMetricEvent { desc, value, time });
625 if metrics_stream.is_full() {
626 drop(metrics_stream);
628 self.flush_metrics_buffer();
629 }
630 }
631
632 #[inline]
633 fn float_metric(&self, desc: &'static StaticMetricMetadata, value: f64) {
634 let time = now();
635 let mut metrics_stream = self.metrics_stream.lock().unwrap();
636 metrics_stream
637 .get_events_mut()
638 .push(FloatMetricEvent { desc, value, time });
639 if metrics_stream.is_full() {
640 drop(metrics_stream);
641 self.flush_metrics_buffer();
643 }
644 }
645
646 #[inline]
647 fn tagged_float_metric(
648 &self,
649 desc: &'static StaticMetricMetadata,
650 properties: &'static PropertySet,
651 value: f64,
652 ) {
653 let time = now();
654 let mut metrics_stream = self.metrics_stream.lock().unwrap();
655 metrics_stream
656 .get_events_mut()
657 .push(TaggedFloatMetricEvent {
658 desc,
659 properties,
660 value,
661 time,
662 });
663 if metrics_stream.is_full() {
664 drop(metrics_stream);
665 self.flush_metrics_buffer();
667 }
668 }
669
670 #[inline]
671 fn tagged_integer_metric(
672 &self,
673 desc: &'static StaticMetricMetadata,
674 properties: &'static PropertySet,
675 value: u64,
676 ) {
677 let time = now();
678 let mut metrics_stream = self.metrics_stream.lock().unwrap();
679 metrics_stream
680 .get_events_mut()
681 .push(TaggedIntegerMetricEvent {
682 desc,
683 properties,
684 value,
685 time,
686 });
687 if metrics_stream.is_full() {
688 drop(metrics_stream);
689 self.flush_metrics_buffer();
691 }
692 }
693
694 #[inline]
695 fn flush_metrics_buffer(&self) {
696 let mut metrics_stream = self.metrics_stream.lock().unwrap();
697 if metrics_stream.is_empty() {
698 return;
699 }
700 let stream_id = metrics_stream.stream_id();
701 let next_offset = metrics_stream.get_block_ref().object_offset()
702 + metrics_stream.get_block_ref().nb_objects();
703 let mut old_event_block = metrics_stream.replace_block(Arc::new(MetricsBlock::new(
704 self.metrics_buffer_size,
705 self.process_id,
706 stream_id,
707 next_offset,
708 )));
709 assert!(!metrics_stream.is_full());
710 Arc::get_mut(&mut old_event_block).unwrap().close();
711 self.get_sink().on_process_metrics_block(old_event_block);
712 }
713
714 fn log_enabled(&self, metadata: &LogMetadata) -> bool {
715 self.get_sink().on_log_enabled(metadata)
716 }
717
718 #[inline]
719 fn log(&self, metadata: &'static LogMetadata, args: fmt::Arguments<'_>) {
720 if !self.log_enabled(metadata) {
721 return;
722 }
723 let time = now();
724 self.get_sink().on_log(metadata, &[], time, args);
725 let mut log_stream = self.log_stream.lock().unwrap();
726 if args.as_str().is_some() {
727 log_stream.get_events_mut().push(LogStaticStrEvent {
728 desc: metadata,
729 time,
730 });
731 } else {
732 log_stream.get_events_mut().push(LogStringEvent {
733 desc: metadata,
734 time,
735 msg: micromegas_transit::DynString(args.to_string()),
736 });
737 }
738 if log_stream.is_full() {
739 drop(log_stream);
741 self.flush_log_buffer();
742 }
743 }
744
745 #[inline]
746 fn log_tagged(
747 &self,
748 desc: &'static LogMetadata,
749 properties: &'static PropertySet,
750 args: fmt::Arguments<'_>,
751 ) {
752 if !self.log_enabled(desc) {
753 return;
754 }
755 let time = now();
756 self.get_sink()
757 .on_log(desc, properties.get_properties(), time, args);
758 let mut log_stream = self.log_stream.lock().unwrap();
759 log_stream.get_events_mut().push(TaggedLogString {
760 desc,
761 properties,
762 time,
763 msg: micromegas_transit::DynString(args.to_string()),
764 });
765 if log_stream.is_full() {
766 drop(log_stream);
768 self.flush_log_buffer();
769 }
770 }
771
772 #[inline]
773 fn log_interop(&self, desc: &LogMetadata, args: fmt::Arguments<'_>) {
774 let time = now();
775 self.get_sink().on_log(desc, &[], time, args);
776 let mut log_stream = self.log_stream.lock().unwrap();
777 if let Some(msg) = args.as_str() {
778 log_stream.get_events_mut().push(LogStaticStrInteropEvent {
779 time,
780 level: desc.level as u32,
781 target: intern_string(desc.target).into(),
782 msg: msg.into(),
783 });
784 } else {
785 log_stream.get_events_mut().push(LogStringInteropEvent {
786 time,
787 level: desc.level as u8,
788 target: intern_string(desc.target).into(),
789 msg: micromegas_transit::DynString(args.to_string()),
790 });
791 }
792 if log_stream.is_full() {
793 drop(log_stream);
795 self.flush_log_buffer();
796 }
797 }
798
799 #[inline]
800 fn flush_log_buffer(&self) {
801 let mut log_stream = self.log_stream.lock().unwrap();
802 if log_stream.is_empty() {
803 return;
804 }
805 let stream_id = log_stream.stream_id();
806 let next_offset =
807 log_stream.get_block_ref().object_offset() + log_stream.get_block_ref().nb_objects();
808 let mut old_event_block = log_stream.replace_block(Arc::new(LogBlock::new(
809 self.logs_buffer_size,
810 self.process_id,
811 stream_id,
812 next_offset,
813 )));
814 assert!(!log_stream.is_full());
815 Arc::get_mut(&mut old_event_block).unwrap().close();
816 self.get_sink().on_process_log_block(old_event_block);
817 }
818
819 #[inline]
820 fn flush_thread_buffer(&self, stream: &mut ThreadStream) {
821 if stream.is_empty() {
822 return;
823 }
824 let next_offset =
825 stream.get_block_ref().object_offset() + stream.get_block_ref().nb_objects();
826 let mut old_block = stream.replace_block(Arc::new(ThreadBlock::new(
827 self.threads_buffer_size,
828 self.process_id,
829 stream.stream_id(),
830 next_offset,
831 )));
832 assert!(!stream.is_full());
833 Arc::get_mut(&mut old_block).unwrap().close();
834 self.get_sink().on_process_thread_block(old_block);
835 }
836}
837
838fn get_cpu_brand() -> String {
839 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
840 return raw_cpuid::CpuId::new()
841 .get_processor_brand_string()
842 .map_or_else(|| "unknown".to_owned(), |b| b.as_str().to_owned());
843 #[cfg(target_arch = "aarch64")]
844 return String::from("aarch64");
845}
846
847pub fn make_process_info(
848 process_id: uuid::Uuid,
849 parent_process_id: Option<uuid::Uuid>,
850 properties: HashMap<String, String>,
851) -> ProcessInfo {
852 let start_ticks = now();
853 let start_time = Utc::now();
854 let cpu_brand = get_cpu_brand();
855 ProcessInfo {
856 process_id,
857 username: whoami::username(),
858 realname: whoami::realname(),
859 exe: std::env::current_exe()
860 .unwrap_or_default()
861 .to_string_lossy()
862 .into_owned(),
863 computer: whoami::devicename(),
864 distro: whoami::distro(),
865 cpu_brand,
866 tsc_frequency: frequency(),
867 start_time,
868 start_ticks,
869 parent_process_id,
870 properties,
871 }
872}