1#[cfg(feature = "rs_tracing")]
15extern crate serde;
16#[cfg(feature = "rs_tracing")]
17extern crate serde_json;
18#[doc(hidden)]
19#[cfg(feature = "rs_tracing")]
20pub use serde_json::{json, json_internal};
21
22#[doc(hidden)]
23pub use internal::*;
24
25#[macro_export]
38macro_rules! trace_activate {
39 () => {
40 trace_state_change!(&$crate::TraceState::Active)
41 };
42}
43
44#[macro_export]
57macro_rules! trace_deactivate {
58 () => {
59 trace_state_change!(&$crate::TraceState::InActive)
60 };
61}
62
63#[macro_export]
81macro_rules! open_trace_file {
82 ($dir:expr) => {
83 trace_to_file_internal!($dir)
84 };
85}
86
87#[macro_export]
91macro_rules! close_trace_file {
92 () => {
93 close_trace_file_internal!()
94 };
95}
96
97#[macro_export]
128macro_rules! trace_scoped {
129 ($name: expr) => {
130 trace_scoped_internal!($name)
131 };
132 ($name: expr, $($json:tt)+) =>{
133 trace_scoped_internal!($name, $($json)+)
134 }
135}
136
137#[macro_export]
166macro_rules! trace_expr {
167 ($name: expr, $expr: expr) => {
168 trace_expr_internal!($name, $expr)
169 };
170 ($name: expr, $expr: expr, $($json:tt)+) =>{
171 trace_expr_internal!($name, $expr, $($json)+)
172 }
173}
174
175#[macro_export]
207macro_rules! trace_begin {
208 ($name: expr) => {
209 trace_duration_internal!($name, $crate::EventType::DurationBegin)
210 };
211 ($name: expr, $($json:tt)+) =>{
212 trace_duration_internal!($name, $crate::EventType::DurationBegin, $($json)+)
213 }
214}
215
216#[macro_export]
248macro_rules! trace_end {
249 ($name: expr) => {
250 trace_duration_internal!($name, $crate::EventType::DurationEnd)
251 };
252 ($name: expr, $($json:tt)+) =>{
253 trace_duration_internal!($name, $crate::EventType::DurationEnd, $($json)+)
254 }
255}
256
257#[cfg(feature = "rs_tracing")]
258mod internal {
259
260 use serde::ser::{Serialize, SerializeStruct, Serializer};
261 use serde_json;
262 use std::fs::{DirBuilder, File};
263 use std::io::{self, BufWriter, Write};
264 use std::mem::transmute;
265 use std::path::{Path, PathBuf};
266 use std::process;
267 use std::sync::atomic::{AtomicBool, Ordering};
268 use std::sync::Mutex;
269 use std::thread::{self, ThreadId};
270 use std::time::SystemTime;
271
272 #[derive(PartialEq)]
273 pub enum TraceState {
274 InActive,
275 Active,
276 }
277
278 static mut TRACER: Mutex<Option<BufWriter<File>>> = Mutex::new(None);
279 static mut TRACE_ACTIVE: AtomicBool = AtomicBool::new(false);
280
281 pub fn trace(event: &TraceEvent) {
282 unsafe {
283 let mut tracer = TRACER.lock().unwrap();
284 if let Some(ref mut file) = *tracer {
285 serde_json::to_writer(&mut *file, event).unwrap();
286 file.write_all(b",\n").unwrap();
287 }
288 }
289 }
290
291 pub fn set_trace_state(state: &'static TraceState) {
292 unsafe {
293 TRACE_ACTIVE.store(*state == TraceState::Active, Ordering::SeqCst);
294 }
295 }
296
297 pub fn is_trace_active() -> bool {
298 unsafe { TRACE_ACTIVE.load(Ordering::SeqCst) }
299 }
300
301 #[doc(hidden)]
302 pub enum EventType {
303 DurationBegin,
304 DurationEnd,
305 Complete,
306 }
307
308 impl Serialize for EventType {
309 #[doc(hidden)]
310 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
311 where
312 S: Serializer,
313 {
314 match *self {
315 EventType::DurationBegin => serializer.serialize_unit_variant("EventType", 0, "B"),
316 EventType::DurationEnd => serializer.serialize_unit_variant("EventType", 1, "E"),
317 EventType::Complete => serializer.serialize_unit_variant("EventType", 2, "X"),
318 }
319 }
320 }
321
322 #[doc(hidden)]
323 pub struct TraceEvent<'a> {
324 name: &'a str,
325 ph: EventType,
326 pub ts: u128,
327 pid: u32,
328 tid: u64,
329 pub dur: Option<u128>,
330 args: Option<serde_json::Value>,
331 }
332
333 impl<'a> Serialize for TraceEvent<'a> {
334 #[doc(hidden)]
335 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
336 where
337 S: Serializer,
338 {
339 let mut event = serializer.serialize_struct("TraceEvent", 7)?;
340 event.serialize_field("name", &self.name)?;
341 event.serialize_field("ph", &self.ph)?;
342 event.serialize_field("ts", &self.ts)?;
343 event.serialize_field("pid", &self.pid)?;
344 event.serialize_field("tid", &self.tid)?;
345 if let Some(ref dur) = self.dur {
346 event.serialize_field("dur", &dur)?;
347 }
348 if let Some(ref args) = self.args {
349 event.serialize_field("args", &args)?;
350 }
351 event.end()
352 }
353 }
354
355 impl<'a> TraceEvent<'a> {
356 #[doc(hidden)]
357 pub fn new(name: &'a str, event_type: EventType, args: Option<serde_json::Value>) -> Self {
358 TraceEvent {
359 name,
360 ph: event_type,
361 ts: precise_time_microsec(),
362 pid: process::id(),
363 tid: unsafe {
364 transmute::<ThreadId, u64>(thread::current().id())
366 },
367 dur: None,
368 args,
369 }
370 }
371 }
372
373 #[doc(hidden)]
374 pub struct EventGuard<'a> {
375 event: TraceEvent<'a>,
376 }
377
378 impl<'a> EventGuard<'a> {
379 #[doc(hidden)]
380 pub fn new(name: &'a str, args: Option<serde_json::Value>) -> EventGuard<'a> {
381 EventGuard {
382 event: TraceEvent::new(name, EventType::Complete, args),
383 }
384 }
385 }
386
387 impl<'a> Drop for EventGuard<'a> {
388 #[doc(hidden)]
389 fn drop(&mut self) {
390 self.event.dur = Some(precise_time_microsec().saturating_sub(self.event.ts));
391 trace(&self.event);
392 }
393 }
394
395 pub fn init_trace_to_file<P: AsRef<Path>>(dir: P) -> io::Result<()> {
396 let mut tracer = unsafe { TRACER.lock().unwrap() };
397 let mut dir_path = PathBuf::new();
398 dir_path.push(dir);
399 let mut file_path = dir_path.clone();
400 file_path.push(process::id().to_string());
401 file_path.set_extension("trace");
402 let file = DirBuilder::new()
403 .recursive(true)
404 .create(dir_path)
405 .and(File::create(file_path))?;
406 let mut writer = BufWriter::new(file);
407 writer.write_all(b"[")?;
408 *tracer = Some(writer);
409 set_trace_state(&TraceState::Active);
410 Ok(())
411 }
412
413 pub fn close_trace_file_fn() {
414 let mut tracer = unsafe { TRACER.lock().unwrap() };
415 if let Some(ref mut file) = *tracer {
416 (*file).flush().unwrap();
417 }
418 *tracer = None;
419 }
420
421 #[doc(hidden)]
422 pub fn precise_time_microsec() -> u128 {
423 SystemTime::now()
424 .duration_since(SystemTime::UNIX_EPOCH)
425 .expect("SystemTime is before UNIX EPOCH")
426 .as_micros()
427 }
428
429 #[doc(hidden)]
430 #[macro_export]
431 macro_rules! trace_state_change {
432 ($state:expr) => {
433 $crate::set_trace_state($state)
434 };
435 }
436
437 #[doc(hidden)]
438 #[macro_export]
439 macro_rules! trace_to_file_internal {
440 ($dir:expr) => {
441 $crate::init_trace_to_file($dir)
442 };
443 }
444
445 #[doc(hidden)]
446 #[macro_export]
447 macro_rules! close_trace_file_internal {
448 () => {
449 $crate::close_trace_file_fn();
450 };
451 }
452
453 #[doc(hidden)]
454 #[macro_export]
455 macro_rules! trace_scoped_internal {
456 ($name: expr) => {
457 let _guard = if $crate::is_trace_active() {
458 Some($crate::EventGuard::new($name, None))
459 }else{
460 None
461 };
462 };
463 ($name: expr, $($json:tt)+) =>{
464 let _guard = if $crate::is_trace_active() {
465 Some($crate::EventGuard::new($name, Some(json!({$($json)+}))))
466 }else{
467 None
468 };
469 }
470}
471
472 #[doc(hidden)]
473 #[macro_export]
474 macro_rules! trace_expr_internal {
475 ($name: expr, $expr: expr) => {
476 if $crate::is_trace_active() {
477 let mut event = $crate::TraceEvent::new($name, $crate::EventType::Complete, None);
478 let result = $expr;
479 event.dur = Some($crate::precise_time_microsec() - event.ts);
480 $crate::trace(&event);
481 result
482 }else{
483 $expr
484 }
485 };
486 ($name: expr, $expr: expr, $($json:tt)+) =>{
487 if $crate::is_trace_active() {
488 let mut event = $crate::TraceEvent::new($name, $crate::EventType::Complete, Some(json!({$($json)+})));
489 let result = $expr;
490 event.dur = Some($crate::precise_time_microsec() - event.ts);
491 $crate::trace(&event);
492 result
493 }else{
494 $expr
495 }
496 }
497}
498
499 #[doc(hidden)]
500 #[macro_export]
501 macro_rules! trace_duration_internal {
502 ($name: expr, $event_type: expr) => {
503 if $crate::is_trace_active() {
504 let event = $crate::TraceEvent::new($name, $event_type, None);
505 $crate::trace(&event);
506 }
507 };
508 ($name: expr, $event_type: expr, $($json:tt)+) =>{
509 if $crate::is_trace_active() {
510 let event = $crate::TraceEvent::new($name, $event_type, Some(json!({$($json)+})));
511 $crate::trace(&event);
512 }
513 }
514}
515} #[cfg(not(feature = "rs_tracing"))]
518mod internal {
519 #[doc(hidden)]
520 #[macro_export]
521 macro_rules! trace_state_change {
522 ($state:expr) => {};
523 }
524
525 #[doc(hidden)]
526 #[macro_export]
527 macro_rules! trace_to_file_internal {
528 ($dir:expr) => {{
529 let result: std::io::Result<()> = Ok(());
530 result
531 }};
532 }
533
534 #[doc(hidden)]
535 #[macro_export]
536 macro_rules! close_trace_file_internal {
537 () => {};
538 }
539
540 #[doc(hidden)]
541 #[macro_export]
542 macro_rules! trace_scoped_internal {
543 ($($some:tt)+) => {};
544 }
545
546 #[doc(hidden)]
547 #[macro_export]
548 macro_rules! trace_expr_internal {
549 ($name:expr, $expr:expr) => {
550 $expr
551 };
552 ($name:expr, $expr:expr, $($json:tt)+) => {
553 $expr
554 };
555 }
556
557 #[doc(hidden)]
558 #[macro_export]
559 macro_rules! trace_duration_internal {
560 ($($some:tt)+) => {};
561 }
562}