shovel logs through api for flutter

This commit is contained in:
John Smith
2022-01-31 22:47:17 -05:00
parent 29b5ec5334
commit 65dabd09c7
11 changed files with 266 additions and 20 deletions

View File

@@ -0,0 +1,141 @@
use crate::intf::*;
use crate::veilid_api::*;
use crate::veilid_core::*;
use crate::xx::*;
use log::{set_boxed_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record};
use once_cell::sync::OnceCell;
struct ApiLoggerInner {
level: LevelFilter,
filter_ignore: Cow<'static, [Cow<'static, str>]>,
_join_handle: JoinHandle<()>,
tx: async_channel::Sender<(VeilidLogLevel, String)>,
}
#[derive(Clone)]
pub struct ApiLogger {
inner: Arc<Mutex<Option<ApiLoggerInner>>>,
}
static API_LOGGER: OnceCell<ApiLogger> = OnceCell::new();
impl ApiLogger {
fn new_inner(level: LevelFilter, update_callback: UpdateCallback) -> ApiLoggerInner {
let (tx, rx) = async_channel::unbounded::<(VeilidLogLevel, String)>();
let _join_handle: JoinHandle<()> = spawn(async move {
loop {
match rx.recv().await {
Ok(v) => {
(update_callback)(VeilidUpdate::Log(v.0, v.1)).await;
}
Err(_) => {
// Nothing to be done here...
break;
}
}
}
});
ApiLoggerInner {
level,
filter_ignore: Default::default(),
_join_handle,
tx,
}
}
pub fn init(log_level: LevelFilter, update_callback: UpdateCallback) {
set_max_level(log_level);
let api_logger = API_LOGGER.get_or_init(|| {
let api_logger = ApiLogger {
inner: Arc::new(Mutex::new(None)),
};
set_boxed_logger(Box::new(api_logger.clone())).expect("failed to set api logger");
api_logger
});
let mut inner = api_logger.inner.lock();
*inner = Some(Self::new_inner(log_level, update_callback));
}
pub fn terminate() {
if let Some(api_logger) = API_LOGGER.get() {
let mut inner = api_logger.inner.lock();
*inner = None;
set_max_level(LevelFilter::Off);
}
}
pub fn change_log_level(log_level: LevelFilter) {
if let Some(api_logger) = API_LOGGER.get() {
if let Some(inner) = &mut *api_logger.inner.lock() {
set_max_level(log_level);
inner.level = log_level;
}
}
}
pub fn add_filter_ignore_str(filter_ignore: &'static str) {
if let Some(api_logger) = API_LOGGER.get() {
if let Some(inner) = &mut *api_logger.inner.lock() {
let mut list = Vec::from(&*inner.filter_ignore);
list.push(Cow::Borrowed(filter_ignore));
inner.filter_ignore = Cow::Owned(list);
}
}
}
}
impl Log for ApiLogger {
fn enabled(&self, metadata: &Metadata<'_>) -> bool {
if let Some(inner) = &mut *self.inner.lock() {
return metadata.level() <= inner.level;
}
false
}
fn log(&self, record: &Record<'_>) {
if let Some(inner) = &mut *self.inner.lock() {
// Skip filtered targets
let skip = match (record.target(), &*inner.filter_ignore) {
(path, ignore) if !ignore.is_empty() => {
// Check that the module path does not match any ignore filters
ignore.iter().any(|v| path.starts_with(&**v))
}
_ => false,
};
if skip {
return;
}
let metadata = record.metadata();
let level = metadata.level();
if level <= inner.level {
let ll = VeilidLogLevel::from_log_level(level);
let file = record.file().unwrap_or("<unknown>");
let loc = if level >= Level::Debug {
if let Some(line) = record.line() {
format!("[{}:{}] ", file, line)
} else {
format!("[{}:<unknown>] ", file)
}
} else {
"".to_owned()
};
let tgt = if record.target().is_empty() {
"".to_owned()
} else {
format!("{}: ", record.target())
};
let s = format!("{}{}{}", tgt, loc, record.args());
let _ = inner.tx.try_send((ll, s));
}
}
}
fn flush(&self) {
// always flushes
}
}

View File

@@ -4,6 +4,7 @@
#[macro_use]
extern crate alloc;
mod api_logger;
mod attachment_manager;
mod callback_state_machine;
mod connection_manager;
@@ -45,3 +46,14 @@ pub fn veilid_version() -> (u32, u32, u32) {
u32::from_str(env!("CARGO_PKG_VERSION_PATCH")).unwrap(),
)
}
pub static DEFAULT_LOG_IGNORE_LIST: [&'static str; 8] = [
"async_std",
"async_io",
"polling",
"rustls",
"async_tungstenite",
"tungstenite",
"netlink_proto",
"netlink_sys",
];

View File

@@ -175,7 +175,7 @@ pub fn config_callback(key: String) -> ConfigCallbackReturn {
match key.as_str() {
"program_name" => Ok(Box::new(String::from("Veilid"))),
"namespace" => Ok(Box::new(String::from(""))),
"log_to_api" => Ok(Box::new(false)),
"api_log_level" => Ok(Box::new(VeilidConfigLogLevel::Off)),
"capabilities.protocol_udp" => Ok(Box::new(true)),
"capabilities.protocol_connect_tcp" => Ok(Box::new(true)),
"capabilities.protocol_accept_tcp" => Ok(Box::new(true)),
@@ -276,7 +276,7 @@ pub async fn test_config() {
let inner = vc.get();
assert_eq!(inner.program_name, String::from("Veilid"));
assert_eq!(inner.namespace, String::from(""));
assert_eq!(inner.log_to_api, false);
assert_eq!(inner.api_log_level, VeilidConfigLogLevel::Off);
assert_eq!(inner.capabilities.protocol_udp, true);
assert_eq!(inner.capabilities.protocol_connect_tcp, true);
assert_eq!(inner.capabilities.protocol_accept_tcp, true);

View File

@@ -5,6 +5,7 @@ pub use debug::*;
pub use crate::rpc_processor::InfoAnswer;
use crate::*;
use api_logger::*;
use attachment_manager::*;
use core::fmt;
use network_manager::NetworkManager;
@@ -1178,6 +1179,11 @@ impl VeilidAPI {
Ok(())
}
// Change api logging level if it is enabled
pub async fn change_api_log_level(&self, log_level: VeilidConfigLogLevel) {
ApiLogger::change_log_level(log_level.to_level_filter());
}
////////////////////////////////////////////////////////////////
// Direct Node Access (pretty much for testing only)

View File

@@ -172,11 +172,39 @@ pub struct VeilidConfigCapabilities {
pub protocol_accept_wss: bool,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum VeilidConfigLogLevel {
Off,
Error,
Warn,
Info,
Debug,
Trace,
}
impl VeilidConfigLogLevel {
pub fn to_level_filter(&self) -> LevelFilter {
match self {
Self::Off => LevelFilter::Off,
Self::Error => LevelFilter::Error,
Self::Warn => LevelFilter::Warn,
Self::Info => LevelFilter::Info,
Self::Debug => LevelFilter::Debug,
Self::Trace => LevelFilter::Trace,
}
}
}
impl Default for VeilidConfigLogLevel {
fn default() -> Self {
Self::Off
}
}
#[derive(Default, Clone)]
pub struct VeilidConfigInner {
pub program_name: String,
pub namespace: String,
pub log_to_api: bool,
pub api_log_level: VeilidConfigLogLevel,
pub capabilities: VeilidConfigCapabilities,
pub protected_store: VeilidConfigProtectedStore,
pub table_store: VeilidConfigTableStore,
@@ -221,7 +249,7 @@ impl VeilidConfig {
let mut inner = self.inner.write();
get_config!(inner.program_name);
get_config!(inner.namespace);
get_config!(inner.log_to_api);
get_config!(inner.api_log_level);
get_config!(inner.capabilities.protocol_udp);
get_config!(inner.capabilities.protocol_connect_tcp);
get_config!(inner.capabilities.protocol_accept_tcp);

View File

@@ -1,3 +1,4 @@
use crate::api_logger::*;
use crate::attachment_manager::*;
use crate::dht::crypto::Crypto;
use crate::intf::*;
@@ -86,6 +87,21 @@ impl VeilidCore {
inner: &mut VeilidCoreInner,
setup: VeilidCoreSetup,
) -> Result<VeilidAPI, String> {
// Start up api logging early if it's in the config
let api_log_level: VeilidConfigLogLevel =
*(setup.config_callback)("api_log_level".to_owned())?
.downcast()
.map_err(|_| "incorrect type for key 'api_log_level'".to_owned())?;
if api_log_level != VeilidConfigLogLevel::Off {
ApiLogger::init(
api_log_level.to_level_filter(),
setup.update_callback.clone(),
);
for ig in crate::DEFAULT_LOG_IGNORE_LIST {
ApiLogger::add_filter_ignore_str(ig);
}
}
trace!("VeilidCore::internal_startup starting");
cfg_if! {
@@ -211,6 +227,8 @@ impl VeilidCore {
}
trace!("VeilidCore::shutdown complete");
ApiLogger::terminate();
}
// stop the node gracefully because the veilid api was dropped