app: use the channel to receive other logs

Add another logger to receive message, events or GST logs
This commit is contained in:
Stéphane Cerveau 2023-11-28 17:00:13 +01:00
parent e410289a13
commit 24121856ee
6 changed files with 138 additions and 18 deletions

8
Cargo.lock generated
View file

@ -529,11 +529,13 @@ name = "gst_pipeline_studio"
version = "0.3.4"
dependencies = [
"anyhow",
"chrono",
"futures-channel",
"futures-executor",
"gst-plugin-gtk4",
"gstreamer",
"gtk4",
"lazy_static",
"log 0.4.14",
"once_cell",
"serde",
@ -764,6 +766,12 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.137"

View file

@ -18,6 +18,8 @@ serde = "1.0"
serde_any = "0.5"
simplelog = "0.11.2"
futures-channel = "0.3"
lazy_static = "1.4"
chrono = "0.4"
[dev-dependencies]
futures-executor = "0.3"

View file

@ -457,15 +457,18 @@ impl GPSApp {
let (ready_tx, ready_rx) = glib::MainContext::channel(glib::Priority::DEFAULT);
let app_weak = self.downgrade();
logger::init_logger(
ready_tx,
ready_tx.clone(),
Settings::log_file_path()
.to_str()
.expect("Unable to convert log file path to a string"),
);
GPSUI::logger::setup_logger_list(self);
let _ = ready_rx.attach(None, move |msg: String| {
logger::init_msg_logger(ready_tx);
GPSUI::logger::setup_logger_list(self, "treeview-app-logger", logger::LogType::App);
GPSUI::logger::setup_logger_list(self, "treeview-msg-logger", logger::LogType::Message);
GPSUI::logger::setup_logger_list(self, "treeview-gst-logger", logger::LogType::Gst);
let _ = ready_rx.attach(None, move |msg: (logger::LogType, String)| {
let app = upgrade_weak!(app_weak, glib::ControlFlow::Break);
GPSUI::logger::add_to_logger_list(&app, &msg);
GPSUI::logger::add_to_logger_list(&app, msg.0, &msg.1);
glib::ControlFlow::Continue
});

View file

@ -279,6 +279,7 @@ impl Player {
fn on_pipeline_message(&self, msg: &gst::MessageRef) {
use gst::MessageView;
GPS_MSG!("{:?}", msg.structure());
match msg.view() {
MessageView::Eos(_) => {
GPS_INFO!("EOS received");

View file

@ -14,6 +14,13 @@ use std::io;
use std::fs::File;
use chrono::Local;
use std::sync::Mutex;
lazy_static::lazy_static! {
static ref MSG_LOGGER: Mutex<Option<MessageLogger>> = Mutex::new(None);
}
#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum LogLevel {
@ -25,6 +32,13 @@ pub enum LogLevel {
Trace,
}
#[derive(Debug, Clone, PartialEq)]
pub enum LogType {
App,
Gst,
Message,
}
impl LogLevel {
pub fn from_u32(value: u32) -> LogLevel {
match value {
@ -77,6 +91,22 @@ macro_rules! GPS_DEBUG (
})
);
#[macro_export]
macro_rules! GPS_MSG (
() => ($crate::print!("\n"));
($($arg:tt)*) => ({
logger::pring_msg_logger(logger::LogType::Message, format_args!($($arg)*).to_string());
})
);
#[macro_export]
macro_rules! GPS_GST_LOG (
() => ($crate::print!("\n"));
($($arg:tt)*) => ({
logger::pring_msg_logger(logger::LogType::Gst, format_args!($($arg)*).to_string());
})
);
#[macro_export]
macro_rules! GPS_TRACE (
() => ($crate::print!("\n"));
@ -86,7 +116,7 @@ macro_rules! GPS_TRACE (
);
struct WriteAdapter {
sender: Sender<String>,
sender: Sender<(LogType, String)>,
buffer: String,
}
@ -97,7 +127,9 @@ impl io::Write for WriteAdapter {
.push_str(&String::from_utf8(buf.to_vec()).unwrap());
if self.buffer.ends_with('\n') {
self.buffer.pop();
self.sender.send(self.buffer.clone()).unwrap();
self.sender
.send((LogType::App, self.buffer.clone()))
.unwrap();
self.buffer = String::from("");
}
@ -120,7 +152,7 @@ fn translate_to_simple_logger(log_level: LogLevel) -> LevelFilter {
}
}
pub fn init_logger(sender: Sender<String>, log_file: &str) {
pub fn init_logger(sender: Sender<(LogType, String)>, log_file: &str) {
simplelog::CombinedLogger::init(vec![
WriteLogger::new(
translate_to_simple_logger(LogLevel::Trace),
@ -169,3 +201,34 @@ pub fn print_log(log_level: LogLevel, msg: String) {
_ => {}
};
}
#[derive(Debug, Clone)]
pub struct MessageLogger {
sender: Sender<(LogType, String)>,
}
impl MessageLogger {
pub fn new(sender: Sender<(LogType, String)>) -> Self {
Self { sender }
}
pub fn print_log(&self, log_type: LogType, msg: String) {
let to_send = format!("{}\t{}", Local::now().format("%H:%M:%S"), msg);
self.sender.send((log_type.clone(), to_send)).unwrap();
}
}
pub fn init_msg_logger(sender: Sender<(LogType, String)>) {
let mut msg_logger = MSG_LOGGER.lock().unwrap();
if msg_logger.is_none() {
// Initialize the variable
*msg_logger = Some(MessageLogger::new(sender));
}
}
pub fn pring_msg_logger(log_type: LogType, msg: String) {
let msg_logger = MSG_LOGGER.lock().unwrap();
if let Some(logger) = msg_logger.as_ref() {
logger.print_log(log_type, msg);
}
}

View file

@ -7,6 +7,7 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::app::GPSApp;
use crate::logger;
use crate::ui::treeview;
use gtk::prelude::*;
use gtk::{gio, glib};
@ -18,18 +19,37 @@ fn reset_logger_list(logger_list: &TreeView) {
String::static_type(),
String::static_type(),
String::static_type(),
String::static_type(),
String::static_type(),
]);
logger_list.set_model(Some(&model));
}
pub fn setup_logger_list(app: &GPSApp) {
treeview::add_column_to_treeview(app, "treeview-logger", "TIME", 0, false);
treeview::add_column_to_treeview(app, "treeview-logger", "LEVEL", 1, false);
treeview::add_column_to_treeview(app, "treeview-logger", "LOG", 2, true);
pub fn setup_logger_list(app: &GPSApp, logger_name: &str, log_type: logger::LogType) {
match log_type {
logger::LogType::App => {
treeview::add_column_to_treeview(app, logger_name, "TIME", 0, false);
treeview::add_column_to_treeview(app, logger_name, "LEVEL", 1, false);
treeview::add_column_to_treeview(app, logger_name, "LOG", 2, true);
}
logger::LogType::Gst => {
treeview::add_column_to_treeview(app, logger_name, "TIME", 0, false);
treeview::add_column_to_treeview(app, logger_name, "LEVEL", 1, false);
treeview::add_column_to_treeview(app, logger_name, "CATEGORY", 2, false);
treeview::add_column_to_treeview(app, logger_name, "FILE", 3, false);
treeview::add_column_to_treeview(app, logger_name, "LOG", 4, true);
}
logger::LogType::Message => {
treeview::add_column_to_treeview(app, logger_name, "TIME", 0, false);
treeview::add_column_to_treeview(app, logger_name, "LEVEL", 1, false);
treeview::add_column_to_treeview(app, logger_name, "LOG", 2, true);
}
}
let logger_list: TreeView = app
.builder
.object("treeview-logger")
.expect("Couldn't get treeview-logger");
.object(logger_name)
.expect("Couldn't get treeview-app-logger");
reset_logger_list(&logger_list);
let gesture = gtk::GestureClick::new();
@ -59,17 +79,40 @@ pub fn setup_logger_list(app: &GPSApp) {
logger_list.add_controller(gesture);
}
pub fn add_to_logger_list(app: &GPSApp, log_entry: &str) {
fn log_tree_id_from_log_type(log_type: logger::LogType) -> String {
match log_type {
logger::LogType::App => String::from("treeview-app-logger"),
logger::LogType::Gst => String::from("treeview-gst-logger"),
logger::LogType::Message => String::from("treeview-msg-logger"),
}
}
pub fn add_to_logger_list(app: &GPSApp, log_type: logger::LogType, log_entry: &str) {
let log_tree_name = log_tree_id_from_log_type(log_type.clone());
let logger_list: TreeView = app
.builder
.object("treeview-logger")
.expect("Couldn't get treeview-logger");
.object(log_tree_name.as_str())
.expect("Couldn't get treeview");
if let Some(model) = logger_list.model() {
let list_store = model
.dynamic_cast::<ListStore>()
.expect("Could not cast to ListStore");
if log_type == logger::LogType::Gst {
let log: Vec<&str> = log_entry.splitn(5, '\t').collect();
list_store.insert_with_values(
Some(0),
&[
(0, &log[0]),
(1, &log[1]),
(2, &log[2]),
(3, &log[3]),
(4, &log[4]),
],
);
} else {
let log: Vec<&str> = log_entry.splitn(3, ' ').collect();
list_store.insert_with_values(Some(0), &[(0, &log[0]), (1, &log[1]), (2, &log[2])]);
}
// Scroll to the first element.
if let Some(model) = logger_list.model() {
if let Some(iter) = model.iter_first() {