From 153d4c7ac5030d9d459343ee097d359664526405 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 2 Nov 2024 09:24:17 -0300 Subject: [PATCH] tracers: queue-levels: Add a signal to force writing log file This way applications can write the queue levels info whenever it wants and does not need to wait for the application to quite. Part-of: --- utils/tracers/src/queue_levels/imp.rs | 114 ++++++++++++++++---------- 1 file changed, 71 insertions(+), 43 deletions(-) diff --git a/utils/tracers/src/queue_levels/imp.rs b/utils/tracers/src/queue_levels/imp.rs index 65c5fe74..8fdae6e3 100644 --- a/utils/tracers/src/queue_levels/imp.rs +++ b/utils/tracers/src/queue_levels/imp.rs @@ -44,7 +44,7 @@ * * By default this is not set. */ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::path::PathBuf; use std::str::FromStr; use std::sync::{Arc, Mutex}; @@ -179,6 +179,7 @@ struct State { queues: HashMap>, log: Vec, settings: Settings, + logs_written: HashSet, } struct LogLine { @@ -239,49 +240,26 @@ impl ObjectImpl for QueueLevels { self.register_hook(TracerHook::PadPushEventPre); } + fn signals() -> &'static [glib::subclass::Signal] { + static SIGNALS: LazyLock> = LazyLock::new(|| { + vec![glib::subclass::Signal::builder("write-log") + .action() + .param_types([Option::::static_type()]) + .class_handler(|_, args| { + let obj = args[0].get::().unwrap(); + + obj.imp().write_log(args[1].get::>().unwrap()); + + None + }) + .build()] + }); + + SIGNALS.as_ref() + } + fn dispose(&self) { - use std::io::prelude::*; - - let state = self.state.lock().unwrap(); - - let mut file = match std::fs::File::create(&state.settings.file) { - Ok(file) => file, - Err(err) => { - gst::error!(CAT, imp = self, "Failed to create file: {err}"); - return; - } - }; - - gst::debug!( - CAT, - imp = self, - "Writing file {}", - state.settings.file.display() - ); - - for LogLine { - timestamp, - name, - idx, - ptr, - cur_level_bytes, - cur_level_time, - cur_level_buffers, - max_size_bytes, - max_size_time, - max_size_buffers, - } in &state.log - { - let res = if let Some(idx) = idx { - writeln!(&mut file, "{timestamp},{name}:{idx},0x{ptr:08x},{cur_level_bytes},{cur_level_time},{cur_level_buffers},{max_size_bytes},{max_size_time},{max_size_buffers}") - } else { - writeln!(&mut file, "{timestamp},{name},0x{ptr:08x},{cur_level_bytes},{cur_level_time},{cur_level_buffers},{max_size_bytes},{max_size_time},{max_size_buffers}") - }; - if let Err(err) = res { - gst::error!(CAT, imp = self, "Failed to write to file: {err}"); - return; - } - } + self.write_log(None); } } @@ -545,4 +523,54 @@ impl QueueLevels { }); } } + + fn write_log(&self, file_path: Option<&str>) { + use std::io::prelude::*; + + let mut state = self.state.lock().unwrap(); + let path = file_path.map_or_else(|| state.settings.file.clone(), PathBuf::from); + let first_write = state.logs_written.contains(&path); + + let mut file = match std::fs::OpenOptions::new() + .append(!first_write) + .create(true) + .open(path.clone()) + { + Ok(file) => file, + Err(err) => { + gst::error!(CAT, imp = self, "Failed to create file: {err}"); + return; + } + }; + + let log = std::mem::take(&mut state.log); + state.logs_written.insert(path); + drop(state); + + gst::debug!(CAT, imp = self, "Writing file {:?}", file); + + for LogLine { + timestamp, + name, + idx, + ptr, + cur_level_bytes, + cur_level_time, + cur_level_buffers, + max_size_bytes, + max_size_time, + max_size_buffers, + } in &log + { + let res = if let Some(idx) = idx { + writeln!(&mut file, "{timestamp},{name}:{idx},0x{ptr:08x},{cur_level_bytes},{cur_level_time},{cur_level_buffers},{max_size_bytes},{max_size_time},{max_size_buffers}") + } else { + writeln!(&mut file, "{timestamp},{name},0x{ptr:08x},{cur_level_bytes},{cur_level_time},{cur_level_buffers},{max_size_bytes},{max_size_time},{max_size_buffers}") + }; + if let Err(err) = res { + gst::error!(CAT, imp = self, "Failed to write to file: {err}"); + return; + } + } + } }