rs_tracing-1.1.0/.cargo_vcs_info.json0000644000000001360000000000100131660ustar { "git": { "sha1": "f3b2aa4f055d2174b8bbdf63f00ea79ff03b2f8e" }, "path_in_vcs": "" }rs_tracing-1.1.0/.gitignore000064400000000000000000000000401046102023000137400ustar 00000000000000 /target/ **/*.rs.bk Cargo.lock rs_tracing-1.1.0/Cargo.toml0000644000000016750000000000100111750ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] name = "rs_tracing" version = "1.1.0" authors = ["Andreas Jonson"] description = "trace events in the trace event format" documentation = "https://docs.rs/rs_tracing/" readme = "README.md" keywords = [ "profiler", "trace", ] license = "MIT" repository = "https://github.com/andjo403/rs_tracing.git" [dependencies.serde] version = "1.0" optional = true [dependencies.serde_json] version = "1.0" optional = true [features] rs_tracing = [ "serde_json", "serde", ] rs_tracing-1.1.0/Cargo.toml.orig000064400000000000000000000007221046102023000146460ustar 00000000000000[package] name = "rs_tracing" version = "1.1.0" authors = ["Andreas Jonson"] readme = "README.md" license = "MIT" description = "trace events in the trace event format" documentation = "https://docs.rs/rs_tracing/" repository = "https://github.com/andjo403/rs_tracing.git" keywords = ["profiler", "trace"] [dependencies] serde_json = { version = "1.0", optional = true } serde = { version = "1.0", optional = true } [features] rs_tracing = ["serde_json", "serde"] rs_tracing-1.1.0/LICENSE000064400000000000000000000020561046102023000127660ustar 00000000000000MIT License Copyright (c) 2018 Andreas Jonson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.rs_tracing-1.1.0/README.md000064400000000000000000000013731046102023000132410ustar 00000000000000Traces to Chrome's [trace_event format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview) ## Example ## Cargo.toml: ```toml rs_tracing = { version = "1.0", features = ["rs_tracing"] } ``` main.rs: ```Rust fn main() { open_trace_file!(".").unwrap(); { trace_scoped!("complete","custom data":"main"); trace_expr!("trace_expr", println!("trace_expr")); trace_begin!("duration"); println!("trace_duration"); trace_end!("duration"); } close_trace_file!(); } ``` also possible to add custom data to all the macros formated like the [serde_json::json!](https://docs.serde.rs/serde_json/macro.json.html) macro e.g. trace_scoped!("complete","custom":230,"more":"data"); rs_tracing-1.1.0/src/lib.rs000064400000000000000000000363021046102023000136650ustar 00000000000000//! rs_tracing is a crate that outputs trace events to a file in the [trace event format]. //! //! This format is used by chrome://tracing the output can also be converted to html //! with [trace2html]. //! //! If the feature rs_tracing is not set in the toml file the macros expand to nothing, //! with the exception of trace_expr that will still execute the expression, //! also all crate dependencies of rs_tracing will be removed. //! //! [trace2html]: https://github.com/catapult-project/catapult/blob/master/tracing/README.md //! [trace event format]: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview# //! #[cfg(feature = "rs_tracing")] extern crate serde; #[cfg(feature = "rs_tracing")] extern crate serde_json; #[doc(hidden)] #[cfg(feature = "rs_tracing")] pub use serde_json::{json, json_internal}; #[doc(hidden)] pub use internal::*; /// Activate tracing /// /// # Examples /// /// ``` /// # #[macro_use] extern crate rs_tracing; /// # fn main() { /// { /// trace_activate!(); /// } /// # } /// ``` #[macro_export] macro_rules! trace_activate { () => { trace_state_change!(&$crate::TraceState::Active) }; } /// Deactivate tracing /// /// # Examples /// /// ``` /// # #[macro_use] extern crate rs_tracing; /// # fn main() { /// { /// trace_deactivate!(); /// } /// # } /// ``` #[macro_export] macro_rules! trace_deactivate { () => { trace_state_change!(&$crate::TraceState::InActive) }; } /// Activates trace and opens a new trace file with the name \.trace in the dir specified. /// /// # Examples /// /// ``` /// # #[macro_use] extern crate rs_tracing; /// # fn main() { /// { /// open_trace_file!("/tmp").unwrap(); /// { /// trace_scoped!("event name"); /// println!("this is timed"); /// } /// close_trace_file!(); /// } /// # } /// ``` #[macro_export] macro_rules! open_trace_file { ($dir:expr) => { trace_to_file_internal!($dir) }; } /// closes trace file /// /// note will not trace the trace_scoped end trace if called from the same scope. #[macro_export] macro_rules! close_trace_file { () => { close_trace_file_internal!() }; } /// Trace time used from invocation until end of current scope. /// /// The event type is [Complete Event (X)] with start time and duration. /// /// $name: name of the trace event. /// /// $json: optional custom data formated as serdes [json] macro. /// /// [Complete Event (X)]: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.lpfof2aylapb /// [json]: https://docs.serde.rs/serde_json/macro.json.html /// # Examples /// /// ``` /// # #[macro_use] extern crate rs_tracing; /// # fn main() { /// { /// trace_scoped!("event name"); /// println!("this is timed"); /// } /// # } /// ``` /// ``` /// # #[macro_use] extern crate rs_tracing; /// # fn main() { /// { /// trace_scoped!("event name","custom":"data","u32":4); /// println!("this is timed"); /// } /// # } /// ``` #[macro_export] macro_rules! trace_scoped { ($name: expr) => { trace_scoped_internal!($name) }; ($name: expr, $($json:tt)+) =>{ trace_scoped_internal!($name, $($json)+) } } /// trace time used for expression to finish. /// /// The event type is [Complete Event (X)] with start time and duration. /// /// $name: name of the trace event. /// /// $expr: expression to trace. /// /// $json: optional custom data formated as serdes [json] macro. /// /// [Complete Event (X)]: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.lpfof2aylapb /// [json]: https://docs.serde.rs/serde_json/macro.json.html /// # Examples /// /// ``` /// # #[macro_use] extern crate rs_tracing; /// # fn main() { /// let result = trace_expr!("event name", { println!("this is timed"); true}); /// assert!(result, "result wasn't true!"); /// # } /// ``` /// ``` /// # #[macro_use] extern crate rs_tracing; /// # fn main() { /// let result = trace_expr!("event name",{ println!("this is timed"); true},"custom":"data","u32":4); /// assert!(result, "result wasn't true!"); /// # } /// ``` #[macro_export] macro_rules! trace_expr { ($name: expr, $expr: expr) => { trace_expr_internal!($name, $expr) }; ($name: expr, $expr: expr, $($json:tt)+) =>{ trace_expr_internal!($name, $expr, $($json)+) } } /// Mark beginning of event, needs to be followed by corresponding trace_end. /// /// The event type is [Duration Event (B)] with an instant time. /// Start and end of the event must be on the same thread. /// If you provide custom data to both the trace_begin and trace_end then /// the arguments will be merged. /// /// $name: name of the trace event. /// /// $json: optional custom data formated as serdes [json] macro. /// /// [Duration Event (B)]: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.nso4gcezn7n1 /// [json]: https://docs.serde.rs/serde_json/macro.json.html /// # Examples /// /// ``` /// # #[macro_use] extern crate rs_tracing; /// # fn main() { /// trace_begin!("event name"); /// println!("this is timed"); /// trace_end!("event name"); /// # } /// ``` /// ``` /// # #[macro_use] extern crate rs_tracing; /// # fn main() { /// trace_begin!("event name","custom":"data"); /// println!("this is timed"); /// trace_end!("event name","u32":4); /// # } /// ``` #[macro_export] macro_rules! trace_begin { ($name: expr) => { trace_duration_internal!($name, $crate::EventType::DurationBegin) }; ($name: expr, $($json:tt)+) =>{ trace_duration_internal!($name, $crate::EventType::DurationBegin, $($json)+) } } /// Mark end of event, needs to be proceeded by corresponding trace_begin. /// /// The event type is [Duration Event (E)] with an instant time. /// Start and end of the event must be on the same thread. /// If you provide custom data to both the trace_begin and trace_end then /// the arguments will be merged. /// /// $name: name of the trace event. /// /// $json: optional custom data formated as serdes [json] macro. /// /// [Duration Event (E)]: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.nso4gcezn7n1 /// [json]: https://docs.serde.rs/serde_json/macro.json.html /// # Examples /// /// ``` /// # #[macro_use] extern crate rs_tracing; /// # fn main() { /// trace_begin!("event name"); /// println!("this is timed"); /// trace_end!("event name"); /// # } /// ``` /// ``` /// # #[macro_use] extern crate rs_tracing; /// # fn main() { /// trace_begin!("event name","custom":"data"); /// println!("this is timed"); /// trace_end!("event name","u32":4); /// # } /// ``` #[macro_export] macro_rules! trace_end { ($name: expr) => { trace_duration_internal!($name, $crate::EventType::DurationEnd) }; ($name: expr, $($json:tt)+) =>{ trace_duration_internal!($name, $crate::EventType::DurationEnd, $($json)+) } } #[cfg(feature = "rs_tracing")] mod internal { use serde::ser::{Serialize, SerializeStruct, Serializer}; use serde_json; use std::fs::{DirBuilder, File}; use std::io::{self, BufWriter, Write}; use std::mem::transmute; use std::path::{Path, PathBuf}; use std::process; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Mutex; use std::thread::{self, ThreadId}; use std::time::SystemTime; #[derive(PartialEq)] pub enum TraceState { InActive, Active, } static mut TRACER: Mutex>> = Mutex::new(None); static mut TRACE_ACTIVE: AtomicBool = AtomicBool::new(false); pub fn trace(event: &TraceEvent) { unsafe { let mut tracer = TRACER.lock().unwrap(); if let Some(ref mut file) = *tracer { serde_json::to_writer(&mut *file, event).unwrap(); file.write_all(b",\n").unwrap(); } } } pub fn set_trace_state(state: &'static TraceState) { unsafe { TRACE_ACTIVE.store(*state == TraceState::Active, Ordering::SeqCst); } } pub fn is_trace_active() -> bool { unsafe { TRACE_ACTIVE.load(Ordering::SeqCst) } } #[doc(hidden)] pub enum EventType { DurationBegin, DurationEnd, Complete, } impl Serialize for EventType { #[doc(hidden)] fn serialize(&self, serializer: S) -> Result where S: Serializer, { match *self { EventType::DurationBegin => serializer.serialize_unit_variant("EventType", 0, "B"), EventType::DurationEnd => serializer.serialize_unit_variant("EventType", 1, "E"), EventType::Complete => serializer.serialize_unit_variant("EventType", 2, "X"), } } } #[doc(hidden)] pub struct TraceEvent<'a> { name: &'a str, ph: EventType, pub ts: u128, pid: u32, tid: u64, pub dur: Option, args: Option, } impl<'a> Serialize for TraceEvent<'a> { #[doc(hidden)] fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut event = serializer.serialize_struct("TraceEvent", 7)?; event.serialize_field("name", &self.name)?; event.serialize_field("ph", &self.ph)?; event.serialize_field("ts", &self.ts)?; event.serialize_field("pid", &self.pid)?; event.serialize_field("tid", &self.tid)?; if let Some(ref dur) = self.dur { event.serialize_field("dur", &dur)?; } if let Some(ref args) = self.args { event.serialize_field("args", &args)?; } event.end() } } impl<'a> TraceEvent<'a> { #[doc(hidden)] pub fn new(name: &'a str, event_type: EventType, args: Option) -> Self { TraceEvent { name, ph: event_type, ts: precise_time_microsec(), pid: process::id(), tid: unsafe { // only want an unique identifier per thread think this is ok. transmute::(thread::current().id()) }, dur: None, args, } } } #[doc(hidden)] pub struct EventGuard<'a> { event: TraceEvent<'a>, } impl<'a> EventGuard<'a> { #[doc(hidden)] pub fn new(name: &'a str, args: Option) -> EventGuard<'a> { EventGuard { event: TraceEvent::new(name, EventType::Complete, args), } } } impl<'a> Drop for EventGuard<'a> { #[doc(hidden)] fn drop(&mut self) { self.event.dur = Some(precise_time_microsec().saturating_sub(self.event.ts)); trace(&self.event); } } pub fn init_trace_to_file>(dir: P) -> io::Result<()> { let mut tracer = unsafe { TRACER.lock().unwrap() }; let mut dir_path = PathBuf::new(); dir_path.push(dir); let mut file_path = dir_path.clone(); file_path.push(process::id().to_string()); file_path.set_extension("trace"); let file = DirBuilder::new() .recursive(true) .create(dir_path) .and(File::create(file_path))?; let mut writer = BufWriter::new(file); writer.write_all(b"[")?; *tracer = Some(writer); set_trace_state(&TraceState::Active); Ok(()) } pub fn close_trace_file_fn() { let mut tracer = unsafe { TRACER.lock().unwrap() }; if let Some(ref mut file) = *tracer { (*file).flush().unwrap(); } *tracer = None; } #[doc(hidden)] pub fn precise_time_microsec() -> u128 { SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .expect("SystemTime is before UNIX EPOCH") .as_micros() } #[doc(hidden)] #[macro_export] macro_rules! trace_state_change { ($state:expr) => { $crate::set_trace_state($state) }; } #[doc(hidden)] #[macro_export] macro_rules! trace_to_file_internal { ($dir:expr) => { $crate::init_trace_to_file($dir) }; } #[doc(hidden)] #[macro_export] macro_rules! close_trace_file_internal { () => { $crate::close_trace_file_fn(); }; } #[doc(hidden)] #[macro_export] macro_rules! trace_scoped_internal { ($name: expr) => { let _guard = if $crate::is_trace_active() { Some($crate::EventGuard::new($name, None)) }else{ None }; }; ($name: expr, $($json:tt)+) =>{ let _guard = if $crate::is_trace_active() { Some($crate::EventGuard::new($name, Some(json!({$($json)+})))) }else{ None }; } } #[doc(hidden)] #[macro_export] macro_rules! trace_expr_internal { ($name: expr, $expr: expr) => { if $crate::is_trace_active() { let mut event = $crate::TraceEvent::new($name, $crate::EventType::Complete, None); let result = $expr; event.dur = Some($crate::precise_time_microsec() - event.ts); $crate::trace(&event); result }else{ $expr } }; ($name: expr, $expr: expr, $($json:tt)+) =>{ if $crate::is_trace_active() { let mut event = $crate::TraceEvent::new($name, $crate::EventType::Complete, Some(json!({$($json)+}))); let result = $expr; event.dur = Some($crate::precise_time_microsec() - event.ts); $crate::trace(&event); result }else{ $expr } } } #[doc(hidden)] #[macro_export] macro_rules! trace_duration_internal { ($name: expr, $event_type: expr) => { if $crate::is_trace_active() { let event = $crate::TraceEvent::new($name, $event_type, None); $crate::trace(&event); } }; ($name: expr, $event_type: expr, $($json:tt)+) =>{ if $crate::is_trace_active() { let event = $crate::TraceEvent::new($name, $event_type, Some(json!({$($json)+}))); $crate::trace(&event); } } } } // mod internal #[cfg(not(feature = "rs_tracing"))] mod internal { #[doc(hidden)] #[macro_export] macro_rules! trace_state_change { ($state:expr) => {}; } #[doc(hidden)] #[macro_export] macro_rules! trace_to_file_internal { ($dir:expr) => {{ let result: std::io::Result<()> = Ok(()); result }}; } #[doc(hidden)] #[macro_export] macro_rules! close_trace_file_internal { () => {}; } #[doc(hidden)] #[macro_export] macro_rules! trace_scoped_internal { ($($some:tt)+) => {}; } #[doc(hidden)] #[macro_export] macro_rules! trace_expr_internal { ($name:expr, $expr:expr) => { $expr }; ($name:expr, $expr:expr, $($json:tt)+) => { $expr }; } #[doc(hidden)] #[macro_export] macro_rules! trace_duration_internal { ($($some:tt)+) => {}; } } // mod internal