#![deny(warnings, clippy::all)]
use babeltrace2_sys::*;
use std::ffi::{CString, NulError};
use std::os::unix::ffi::OsStrExt;
use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::Duration;
use std::{process, thread};
use structopt::StructOpt;
use url::Url;
#[derive(StructOpt, Debug)]
struct Opts {
#[structopt(subcommand)]
cmd: Cmd,
}
#[derive(StructOpt, Debug)]
enum Cmd {
Fs {
#[structopt(long)]
no_events: bool,
#[structopt(long)]
trace_name: Option<String>,
#[structopt(long = "offset-ns")]
clock_class_offset_ns: Option<i64>,
#[structopt(long = "offset-s")]
clock_class_offset_s: Option<i64>,
#[structopt(long = "unix-epoch")]
force_clock_class_origin_unix_epoch: Option<bool>,
#[structopt(name = "input", required = true, min_values = 1)]
inputs: Vec<PathBuf>,
},
LttngLive {
#[structopt(long)]
no_events: bool,
#[structopt(long, short = "r", default_value = "100000")]
retry_duration_us: u64,
#[structopt(long, verbatim_doc_comment)]
session_not_found_action: Option<SessionNotFoundAction>,
#[structopt(verbatim_doc_comment)]
url: Url,
},
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
match do_main() {
Err(e) => {
log::error!("{}", e);
Err(e)
}
Ok(()) => Ok(()),
}
}
fn do_main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("trace")).init();
let opts = Opts::from_args();
let running = Arc::new(AtomicUsize::new(0));
let r = running.clone();
ctrlc::set_handler(move || {
let prev = r.fetch_add(1, Ordering::SeqCst);
if prev == 0 {
println!("Exiting...");
} else {
process::exit(0);
}
})
.expect("Error setting Ctrl-C handler");
match opts.cmd {
Cmd::Fs {
no_events,
trace_name,
clock_class_offset_ns,
clock_class_offset_s,
force_clock_class_origin_unix_epoch,
inputs,
} => {
let trace_name: Option<CString> =
trace_name.map(|n| CString::new(n.as_bytes())).transpose()?;
let input_cstrings: Vec<CString> = inputs
.iter()
.map(|p| CString::new(p.as_os_str().as_bytes()))
.collect::<Result<Vec<CString>, NulError>>()?;
let inputs = input_cstrings
.iter()
.map(|i| i.as_c_str())
.collect::<Vec<_>>();
let params = CtfPluginSourceFsInitParams::new(
trace_name.as_deref(),
clock_class_offset_ns,
clock_class_offset_s,
force_clock_class_origin_unix_epoch,
&inputs,
)?;
let ctf_iter = CtfIterator::new(LoggingLevel::Warn, ¶ms)?;
println!("------------------------------------------------------------");
println!("Trace Properties");
println!("------------------------------------------------------------");
println!("{:#?}", ctf_iter.trace_properties());
println!();
println!("------------------------------------------------------------");
println!("Stream Properties");
println!("------------------------------------------------------------");
for s in ctf_iter.stream_properties().iter() {
println!("{:#?}", s);
}
println!();
if !no_events {
for event in ctf_iter {
if running.load(Ordering::SeqCst) != 0 {
break;
}
let event = event?;
println!("{}", event);
}
}
}
Cmd::LttngLive {
no_events,
retry_duration_us,
url,
session_not_found_action,
} => {
let url = CString::new(url.to_string().as_bytes())?;
let params = CtfPluginSourceLttnLiveInitParams::new(&url, session_not_found_action)?;
let mut ctf_stream = CtfStream::new(LoggingLevel::Warn, ¶ms)?;
let retry_duration = Duration::from_micros(retry_duration_us);
let mut metadata_shown = false;
loop {
if running.load(Ordering::SeqCst) != 0 {
break;
}
match ctf_stream.update()? {
RunStatus::Ok => (),
RunStatus::TryAgain => {
thread::sleep(retry_duration);
continue;
}
RunStatus::End => break,
}
if ctf_stream.has_metadata() && !metadata_shown {
metadata_shown = true;
println!("------------------------------------------------------------");
println!("Trace Properties");
println!("------------------------------------------------------------");
println!("{:#?}", ctf_stream.trace_properties());
println!();
println!("------------------------------------------------------------");
println!("Stream Properties");
println!("------------------------------------------------------------");
for s in ctf_stream.stream_properties().iter() {
println!("{:#?}", s);
}
println!();
if no_events {
break;
}
}
for event in ctf_stream.events_chunk() {
if running.load(Ordering::SeqCst) != 0 {
break;
}
println!("{}", event);
}
}
}
}
Ok(())
}
pub mod proxy_plugin_descriptors {
use babeltrace2_sys::ffi::*;
use babeltrace2_sys::proxy_plugin_descriptors::*;
#[used]
#[link_section = "__bt_plugin_descriptors"]
pub static PLUGIN_DESC_PTR: __bt_plugin_descriptor_ptr =
__bt_plugin_descriptor_ptr(&PLUGIN_DESC);
#[used]
#[link_section = "__bt_plugin_component_class_descriptors"]
pub static SINK_COMP_DESC_PTR: __bt_plugin_component_class_descriptor_ptr =
__bt_plugin_component_class_descriptor_ptr(&SINK_COMP_DESC);
#[used]
#[link_section = "__bt_plugin_component_class_descriptor_attributes"]
pub static SINK_COMP_CLASS_INIT_ATTR_PTR: __bt_plugin_component_class_descriptor_attribute_ptr =
__bt_plugin_component_class_descriptor_attribute_ptr(&SINK_COMP_CLASS_INIT_ATTR);
#[used]
#[link_section = "__bt_plugin_component_class_descriptor_attributes"]
pub static SINK_COMP_CLASS_FINI_ATTR_PTR: __bt_plugin_component_class_descriptor_attribute_ptr =
__bt_plugin_component_class_descriptor_attribute_ptr(&SINK_COMP_CLASS_FINI_ATTR);
#[used]
#[link_section = "__bt_plugin_component_class_descriptor_attributes"]
pub static SINK_COMP_CLASS_GRAPH_CONF_ATTR_PTR:
__bt_plugin_component_class_descriptor_attribute_ptr =
__bt_plugin_component_class_descriptor_attribute_ptr(&SINK_COMP_CLASS_GRAPH_CONF_ATTR);
}
pub mod utils_plugin_descriptors {
use babeltrace2_sys::ffi::*;
#[link(
name = "babeltrace-plugin-utils",
kind = "static",
modifiers = "+whole-archive"
)]
extern "C" {
pub static __bt_plugin_descriptor_auto_ptr: *const __bt_plugin_descriptor;
}
}
pub mod ctf_plugin_descriptors {
use babeltrace2_sys::ffi::*;
#[link(
name = "babeltrace-plugin-ctf",
kind = "static",
modifiers = "+whole-archive"
)]
extern "C" {
pub static __bt_plugin_descriptor_auto_ptr: *const __bt_plugin_descriptor;
}
}