api and log refactor

This commit is contained in:
John Smith 2022-07-01 12:13:52 -04:00
parent f409c84778
commit c106d324c8
25 changed files with 662 additions and 501 deletions

1
Cargo.lock generated
View File

@ -5155,7 +5155,6 @@ dependencies = [
"ctrlc", "ctrlc",
"daemonize", "daemonize",
"directories", "directories",
"failure",
"flume", "flume",
"futures-util", "futures-util",
"hostname", "hostname",

View File

@ -3,6 +3,7 @@ use crate::tools::*;
use crate::veilid_client_capnp::*; use crate::veilid_client_capnp::*;
use capnp::capability::Promise; use capnp::capability::Promise;
use capnp_rpc::{pry, rpc_twoparty_capnp, twoparty, Disconnector, RpcSystem}; use capnp_rpc::{pry, rpc_twoparty_capnp, twoparty, Disconnector, RpcSystem};
use serde::de::DeserializeOwned;
use std::cell::RefCell; use std::cell::RefCell;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::rc::Rc; use std::rc::Rc;
@ -28,6 +29,30 @@ macro_rules! pry_result {
}; };
} }
fn map_to_internal_error<T: ToString>(e: T) -> VeilidAPIError {
VeilidAPIError::Internal {
message: e.to_string(),
}
}
fn decode_api_result<T: DeserializeOwned + fmt::Debug>(
reader: &api_result::Reader,
) -> Result<T, VeilidAPIError> {
match reader.which().map_err(map_to_internal_error)? {
api_result::Which::Ok(v) => {
let ok_val = v.map_err(map_to_internal_error)?;
let res: T = veilid_core::deserialize_json(ok_val).map_err(map_to_internal_error)?;
Ok(res)
}
api_result::Which::Err(e) => {
let err_val = e.map_err(map_to_internal_error)?;
let res: VeilidAPIError =
veilid_core::deserialize_json(err_val).map_err(map_to_internal_error)?;
Err(res)
}
}
}
struct VeilidClientImpl { struct VeilidClientImpl {
comproc: CommandProcessor, comproc: CommandProcessor,
} }
@ -254,7 +279,13 @@ impl ClientApiConnection {
}; };
let request = server.borrow().attach_request(); let request = server.borrow().attach_request();
let response = request.send().promise.await.map_err(map_to_string)?; let response = request.send().promise.await.map_err(map_to_string)?;
response.get().map(drop).map_err(map_to_string) let reader = response
.get()
.map_err(map_to_string)?
.get_result()
.map_err(map_to_string)?;
let res: Result<(), VeilidAPIError> = decode_api_result(&reader);
res.map_err(map_to_string)
} }
pub async fn server_detach(&mut self) -> Result<(), String> { pub async fn server_detach(&mut self) -> Result<(), String> {
@ -269,7 +300,13 @@ impl ClientApiConnection {
}; };
let request = server.borrow().detach_request(); let request = server.borrow().detach_request();
let response = request.send().promise.await.map_err(map_to_string)?; let response = request.send().promise.await.map_err(map_to_string)?;
response.get().map(drop).map_err(map_to_string) let reader = response
.get()
.map_err(map_to_string)?
.get_result()
.map_err(map_to_string)?;
let res: Result<(), VeilidAPIError> = decode_api_result(&reader);
res.map_err(map_to_string)
} }
pub async fn server_shutdown(&mut self) -> Result<(), String> { pub async fn server_shutdown(&mut self) -> Result<(), String> {
@ -294,18 +331,47 @@ impl ClientApiConnection {
inner inner
.server .server
.as_ref() .as_ref()
.ok_or_else(|| "Not connected, ignoring attach request".to_owned())? .ok_or_else(|| "Not connected, ignoring debug request".to_owned())?
.clone() .clone()
}; };
let mut request = server.borrow().debug_request(); let mut request = server.borrow().debug_request();
request.get().set_what(&what); request.get().set_command(&what);
let response = request.send().promise.await.map_err(map_to_string)?; let response = request.send().promise.await.map_err(map_to_string)?;
response let reader = response
.get() .get()
.map_err(map_to_string)? .map_err(map_to_string)?
.get_output() .get_result()
.map(|o| o.to_owned()) .map_err(map_to_string)?;
.map_err(map_to_string) let res: Result<String, VeilidAPIError> = decode_api_result(&reader);
res.map_err(map_to_string)
}
pub async fn server_change_log_level(
&mut self,
layer: String,
log_level: VeilidConfigLogLevel,
) -> Result<(), String> {
trace!("ClientApiConnection::change_log_level");
let server = {
let inner = self.inner.borrow();
inner
.server
.as_ref()
.ok_or_else(|| "Not connected, ignoring change_log_level request".to_owned())?
.clone()
};
let mut request = server.borrow().change_log_level_request();
request.get().set_layer(&layer);
let log_level_json = veilid_core::serialize_json(&log_level);
request.get().set_log_level(&log_level_json);
let response = request.send().promise.await.map_err(map_to_string)?;
let reader = response
.get()
.map_err(map_to_string)?
.get_result()
.map_err(map_to_string)?;
let res: Result<(), VeilidAPIError> = decode_api_result(&reader);
res.map_err(map_to_string)
} }
// Start Client API connection // Start Client API connection

View File

@ -8,6 +8,19 @@ use std::net::SocketAddr;
use std::rc::Rc; use std::rc::Rc;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use veilid_core::xx::{Eventual, EventualCommon}; use veilid_core::xx::{Eventual, EventualCommon};
use veilid_core::VeilidConfigLogLevel;
pub fn convert_loglevel(s: &str) -> Result<VeilidConfigLogLevel, String> {
match s.to_ascii_lowercase().as_str() {
"off" => Ok(VeilidConfigLogLevel::Off),
"error" => Ok(VeilidConfigLogLevel::Error),
"warn" => Ok(VeilidConfigLogLevel::Warn),
"info" => Ok(VeilidConfigLogLevel::Info),
"debug" => Ok(VeilidConfigLogLevel::Debug),
"trace" => Ok(VeilidConfigLogLevel::Trace),
_ => Err(format!("Invalid log level: {}", s)),
}
}
#[derive(PartialEq, Clone)] #[derive(PartialEq, Clone)]
pub enum ConnectionState { pub enum ConnectionState {
@ -97,6 +110,7 @@ shutdown - shut the server down
attach - attach the server to the Veilid network attach - attach the server to the Veilid network
detach - detach the server from the Veilid network detach - detach the server from the Veilid network
debug - send a debugging command to the Veilid server debug - send a debugging command to the Veilid server
change_log_level - change the log level for a tracing layer
"#, "#,
); );
let ui = self.ui(); let ui = self.ui();
@ -131,7 +145,7 @@ debug - send a debugging command to the Veilid server
let ui = self.ui(); let ui = self.ui();
spawn_detached_local(async move { spawn_detached_local(async move {
if let Err(e) = capi.server_attach().await { if let Err(e) = capi.server_attach().await {
error!("Server command 'attach' failed to execute: {}", e); error!("Server command 'attach' failed: {}", e);
} }
ui.send_callback(callback); ui.send_callback(callback);
}); });
@ -144,7 +158,7 @@ debug - send a debugging command to the Veilid server
let ui = self.ui(); let ui = self.ui();
spawn_detached_local(async move { spawn_detached_local(async move {
if let Err(e) = capi.server_detach().await { if let Err(e) = capi.server_detach().await {
error!("Server command 'detach' failed to execute: {}", e); error!("Server command 'detach' failed: {}", e);
} }
ui.send_callback(callback); ui.send_callback(callback);
}); });
@ -170,7 +184,40 @@ debug - send a debugging command to the Veilid server
match capi.server_debug(rest.unwrap_or_default()).await { match capi.server_debug(rest.unwrap_or_default()).await {
Ok(output) => ui.display_string_dialog("Debug Output", output, callback), Ok(output) => ui.display_string_dialog("Debug Output", output, callback),
Err(e) => { Err(e) => {
error!("Server command 'debug' failed to execute: {}", e); error!("Server command 'debug' failed: {}", e);
ui.send_callback(callback);
}
}
});
Ok(())
}
pub fn cmd_change_log_level(
&self,
rest: Option<String>,
callback: UICallback,
) -> Result<(), String> {
trace!("CommandProcessor::cmd_change_log_level");
let mut capi = self.capi();
let ui = self.ui();
spawn_detached_local(async move {
let (layer, rest) = Self::word_split(&rest.unwrap_or_default());
let log_level = match convert_loglevel(&rest.unwrap_or_default()) {
Ok(v) => v,
Err(e) => {
error!("failed to change log level: {}", e);
ui.send_callback(callback);
return;
}
};
match capi.server_change_log_level(layer, log_level).await {
Ok(()) => {
info!("Log level changed");
ui.send_callback(callback);
}
Err(e) => {
error!("Server command 'change_log_level' failed: {}", e);
ui.send_callback(callback); ui.send_callback(callback);
} }
} }
@ -190,6 +237,7 @@ debug - send a debugging command to the Veilid server
"attach" => self.cmd_attach(callback), "attach" => self.cmd_attach(callback),
"detach" => self.cmd_detach(callback), "detach" => self.cmd_detach(callback),
"debug" => self.cmd_debug(rest, callback), "debug" => self.cmd_debug(rest, callback),
"change_log_level" => self.cmd_change_log_level(rest, callback),
_ => { _ => {
let ui = self.ui(); let ui = self.ui();
ui.send_callback(callback); ui.send_callback(callback);

View File

@ -10,14 +10,10 @@ cfg_if! {
use send_wrapper::*; use send_wrapper::*;
struct ApiLoggerInner { struct ApiLoggerInner {
max_level: Option<VeilidLogLevel>,
filter_ignore: Cow<'static, [Cow<'static, str>]>,
update_callback: SendWrapper<UpdateCallback>, update_callback: SendWrapper<UpdateCallback>,
} }
} else { } else {
struct ApiLoggerInner { struct ApiLoggerInner {
max_level: Option<VeilidLogLevel>,
filter_ignore: Cow<'static, [Cow<'static, str>]>,
update_callback: UpdateCallback, update_callback: UpdateCallback,
} }
} }
@ -31,21 +27,14 @@ pub struct ApiTracingLayer {
static API_LOGGER: OnceCell<ApiTracingLayer> = OnceCell::new(); static API_LOGGER: OnceCell<ApiTracingLayer> = OnceCell::new();
impl ApiTracingLayer { impl ApiTracingLayer {
fn new_inner( fn new_inner(update_callback: UpdateCallback) -> ApiLoggerInner {
max_level: Option<VeilidLogLevel>,
update_callback: UpdateCallback,
) -> ApiLoggerInner {
cfg_if! { cfg_if! {
if #[cfg(target_arch = "wasm32")] { if #[cfg(target_arch = "wasm32")] {
ApiLoggerInner { ApiLoggerInner {
max_level,
filter_ignore: Default::default(),
update_callback: SendWrapper::new(update_callback), update_callback: SendWrapper::new(update_callback),
} }
} else { } else {
ApiLoggerInner { ApiLoggerInner {
max_level,
filter_ignore: Default::default(),
update_callback, update_callback,
} }
} }
@ -53,11 +42,11 @@ impl ApiTracingLayer {
} }
#[instrument(level = "debug", skip(update_callback))] #[instrument(level = "debug", skip(update_callback))]
pub async fn init(max_level: Option<VeilidLogLevel>, update_callback: UpdateCallback) { pub async fn init(update_callback: UpdateCallback) {
let api_logger = API_LOGGER.get_or_init(|| ApiTracingLayer { let api_logger = API_LOGGER.get_or_init(|| ApiTracingLayer {
inner: Arc::new(Mutex::new(None)), inner: Arc::new(Mutex::new(None)),
}); });
let apilogger_inner = Some(Self::new_inner(max_level, update_callback)); let apilogger_inner = Some(Self::new_inner(update_callback));
*api_logger.inner.lock() = apilogger_inner; *api_logger.inner.lock() = apilogger_inner;
} }
@ -76,52 +65,9 @@ impl ApiTracingLayer {
}) })
.clone() .clone()
} }
#[instrument(level = "trace")]
pub fn change_api_log_level(max_level: Option<VeilidLogLevel>) {
if let Some(api_logger) = API_LOGGER.get() {
if let Some(inner) = &mut *api_logger.inner.lock() {
inner.max_level = max_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<S: Subscriber + for<'a> registry::LookupSpan<'a>> Layer<S> for ApiTracingLayer { impl<S: Subscriber + for<'a> registry::LookupSpan<'a>> Layer<S> for ApiTracingLayer {
fn enabled(&self, metadata: &tracing::Metadata<'_>, _: layer::Context<'_, S>) -> bool {
if let Some(inner) = &mut *self.inner.lock() {
// Skip things that are out of our level
if let Some(max_level) = inner.max_level {
if VeilidLogLevel::from_tracing_level(*metadata.level()) > max_level {
return false;
}
} else {
return false;
}
// Skip filtered targets
let skip = match (metadata.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,
};
!skip
} else {
false
}
}
fn on_new_span( fn on_new_span(
&self, &self,
attrs: &tracing::span::Attributes<'_>, attrs: &tracing::span::Attributes<'_>,
@ -161,23 +107,16 @@ impl<S: Subscriber + for<'a> registry::LookupSpan<'a>> Layer<S> for ApiTracingLa
event.record(&mut recorder); event.record(&mut recorder);
let meta = event.metadata(); let meta = event.metadata();
let level = meta.level(); let level = meta.level();
if let Some(max_level) = inner.max_level { let log_level = VeilidLogLevel::from_tracing_level(*level);
if VeilidLogLevel::from_tracing_level(*level) <= max_level {
let log_level = VeilidLogLevel::from_tracing_level(*level);
let origin = meta let origin = meta
.file() .file()
.and_then(|file| meta.line().map(|ln| format!("{}:{}", file, ln))) .and_then(|file| meta.line().map(|ln| format!("{}:{}", file, ln)))
.unwrap_or_default(); .unwrap_or_default();
let message = format!("{} {}", origin, recorder); let message = format!("{} {}", origin, recorder);
(inner.update_callback)(VeilidUpdate::Log(VeilidStateLog { (inner.update_callback)(VeilidUpdate::Log(VeilidStateLog { log_level, message }))
log_level,
message,
}))
}
}
} }
} }
} }
@ -232,64 +171,3 @@ impl core::default::Default for StringRecorder {
StringRecorder::new() StringRecorder::new()
} }
} }
impl log::Log for ApiTracingLayer {
fn enabled(&self, metadata: &log::Metadata<'_>) -> bool {
if let Some(inner) = &mut *self.inner.lock() {
if let Some(max_level) = inner.max_level {
return VeilidLogLevel::from_log_level(metadata.level()) <= max_level;
}
}
false
}
fn log(&self, record: &log::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();
let log_level = VeilidLogLevel::from_log_level(level);
if let Some(max_level) = inner.max_level {
if log_level <= max_level {
let file = record.file().unwrap_or("<unknown>");
let loc = if level >= log::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 message = format!("{}{}{}", tgt, loc, record.args());
(inner.update_callback)(VeilidUpdate::Log(VeilidStateLog {
log_level,
message,
}))
}
}
}
}
fn flush(&self) {
// always flushes
}
}

View File

@ -59,21 +59,11 @@ impl ServicesContext {
#[instrument(err, skip_all)] #[instrument(err, skip_all)]
pub async fn startup(&mut self) -> Result<(), VeilidAPIError> { pub async fn startup(&mut self) -> Result<(), VeilidAPIError> {
let api_log_level: VeilidConfigLogLevel = self.config.get().api_log_level;
if api_log_level != VeilidConfigLogLevel::Off {
ApiTracingLayer::init(
api_log_level.to_veilid_log_level(),
self.update_callback.clone(),
)
.await;
for ig in crate::DEFAULT_LOG_IGNORE_LIST {
ApiTracingLayer::add_filter_ignore_str(ig);
}
info!("Veilid API logging initialized");
}
info!("Veilid API starting up"); info!("Veilid API starting up");
info!("init api tracing");
ApiTracingLayer::init(self.update_callback.clone()).await;
// Set up protected store // Set up protected store
trace!("init protected store"); trace!("init protected store");
let protected_store = ProtectedStore::new(self.config.clone()); let protected_store = ProtectedStore::new(self.config.clone());

View File

@ -30,6 +30,7 @@ mod routing_table;
mod rpc_processor; mod rpc_processor;
mod veilid_api; mod veilid_api;
mod veilid_config; mod veilid_config;
mod veilid_layer_filter;
mod veilid_rng; mod veilid_rng;
#[macro_use] #[macro_use]
@ -40,6 +41,7 @@ pub use self::attachment_manager::AttachmentState;
pub use self::core_context::{api_startup, api_startup_json, UpdateCallback}; pub use self::core_context::{api_startup, api_startup_json, UpdateCallback};
pub use self::veilid_api::*; pub use self::veilid_api::*;
pub use self::veilid_config::*; pub use self::veilid_config::*;
pub use self::veilid_layer_filter::*;
pub mod veilid_capnp { pub mod veilid_capnp {
include!(concat!(env!("OUT_DIR"), "/proto/veilid_capnp.rs")); include!(concat!(env!("OUT_DIR"), "/proto/veilid_capnp.rs"));

View File

@ -169,7 +169,6 @@ fn config_callback(key: String) -> ConfigCallbackReturn {
match key.as_str() { match key.as_str() {
"program_name" => Ok(Box::new(String::from("Veilid"))), "program_name" => Ok(Box::new(String::from("Veilid"))),
"namespace" => Ok(Box::new(String::from(""))), "namespace" => Ok(Box::new(String::from(""))),
"api_log_level" => Ok(Box::new(VeilidConfigLogLevel::Off)),
"capabilities.protocol_udp" => Ok(Box::new(true)), "capabilities.protocol_udp" => Ok(Box::new(true)),
"capabilities.protocol_connect_tcp" => Ok(Box::new(true)), "capabilities.protocol_connect_tcp" => Ok(Box::new(true)),
"capabilities.protocol_accept_tcp" => Ok(Box::new(true)), "capabilities.protocol_accept_tcp" => Ok(Box::new(true)),

View File

@ -1861,12 +1861,6 @@ impl VeilidAPI {
.map_err(|e| VeilidAPIError::Internal { message: e }) .map_err(|e| VeilidAPIError::Internal { message: e })
} }
// Change api logging level if it is enabled
#[instrument(skip(self))]
pub async fn change_api_log_level(&self, log_level: VeilidConfigLogLevel) {
ApiTracingLayer::change_api_log_level(log_level.to_veilid_log_level());
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Direct Node Access (pretty much for testing only) // Direct Node Access (pretty much for testing only)

View File

@ -223,6 +223,16 @@ impl VeilidConfigLogLevel {
Some(VeilidLogLevel::Trace) => Self::Trace, Some(VeilidLogLevel::Trace) => Self::Trace,
} }
} }
pub fn from_tracing_level_filter(level: level_filters::LevelFilter) -> Self {
match level {
level_filters::LevelFilter::OFF => Self::Off,
level_filters::LevelFilter::ERROR => Self::Error,
level_filters::LevelFilter::WARN => Self::Warn,
level_filters::LevelFilter::INFO => Self::Info,
level_filters::LevelFilter::DEBUG => Self::Debug,
level_filters::LevelFilter::TRACE => Self::Trace,
}
}
} }
impl Default for VeilidConfigLogLevel { impl Default for VeilidConfigLogLevel {
fn default() -> Self { fn default() -> Self {

View File

@ -0,0 +1,91 @@
use super::*;
use crate::xx::*;
use tracing::level_filters::LevelFilter;
use tracing::subscriber;
use tracing_subscriber::layer;
struct VeilidLayerFilterInner {
max_level: LevelFilter,
ignore_list: Vec<String>,
}
#[derive(Clone)]
pub struct VeilidLayerFilter {
inner: Arc<RwLock<VeilidLayerFilterInner>>,
}
impl VeilidLayerFilter {
pub fn new(
max_level: VeilidConfigLogLevel,
ignore_list: Option<Vec<String>>,
) -> VeilidLayerFilter {
Self {
inner: Arc::new(RwLock::new(VeilidLayerFilterInner {
max_level: max_level.to_tracing_level_filter(),
ignore_list: ignore_list
.unwrap_or_else(|| DEFAULT_LOG_IGNORE_LIST.map(|x| x.to_owned()).to_vec()),
})),
}
}
pub fn max_level(&self) -> VeilidConfigLogLevel {
let inner = self.inner.read();
VeilidConfigLogLevel::from_tracing_level_filter(inner.max_level)
}
pub fn ignore_list(&self) -> Vec<String> {
let inner = self.inner.read();
inner.ignore_list.clone()
}
pub fn set_max_level(&self, level: VeilidConfigLogLevel) {
{
let mut inner = self.inner.write();
inner.max_level = level.to_tracing_level_filter();
}
callsite::rebuild_interest_cache();
}
pub fn set_ignore_list(&self, ignore_list: Option<Vec<String>>) {
{
let mut inner = self.inner.write();
inner.ignore_list = ignore_list
.unwrap_or_else(|| DEFAULT_LOG_IGNORE_LIST.map(|x| x.to_owned()).to_vec());
}
callsite::rebuild_interest_cache();
}
}
impl<S: tracing::Subscriber> layer::Filter<S> for VeilidLayerFilter {
fn enabled(&self, metadata: &tracing::Metadata<'_>, _: &layer::Context<'_, S>) -> bool {
let inner = self.inner.read();
if *metadata.level() > inner.max_level {
false
} else {
true
}
}
fn callsite_enabled(
&self,
metadata: &'static tracing::Metadata<'static>,
) -> subscriber::Interest {
let inner = self.inner.read();
let skip = inner
.ignore_list
.iter()
.any(|v| metadata.target().starts_with(&**v));
if skip {
subscriber::Interest::never()
} else if *metadata.level() > inner.max_level {
subscriber::Interest::never()
} else {
subscriber::Interest::always()
}
}
fn max_level_hint(&self) -> Option<LevelFilter> {
let inner = self.inner.read();
Some(inner.max_level)
}
}

View File

@ -7,7 +7,6 @@ Future<VeilidConfig> getDefaultVeilidConfig() async {
return VeilidConfig( return VeilidConfig(
programName: "Veilid Plugin Test", programName: "Veilid Plugin Test",
namespace: "", namespace: "",
apiLogLevel: VeilidConfigLogLevel.info,
capabilities: VeilidConfigCapabilities( capabilities: VeilidConfigCapabilities(
protocolUDP: !kIsWeb, protocolUDP: !kIsWeb,
protocolConnectTCP: !kIsWeb, protocolConnectTCP: !kIsWeb,

View File

@ -59,7 +59,7 @@ VeilidConfigLogLevel convertToVeilidConfigLogLevel(LogLevel? level) {
void setRootLogLevel(LogLevel? level) { void setRootLogLevel(LogLevel? level) {
Loggy('').level = getLogOptions(level); Loggy('').level = getLogOptions(level);
Veilid.instance.changeApiLogLevel(convertToVeilidConfigLogLevel(level)); Veilid.instance.changeLogLevel("all", convertToVeilidConfigLogLevel(level));
} }
void initLoggy() { void initLoggy() {
@ -81,22 +81,26 @@ void main() {
logging: VeilidWASMConfigLogging( logging: VeilidWASMConfigLogging(
performance: VeilidWASMConfigLoggingPerformance( performance: VeilidWASMConfigLoggingPerformance(
enabled: true, enabled: true,
level: VeilidLogLevel.trace, level: VeilidConfigLogLevel.debug,
logsInTimings: true, logsInTimings: true,
logsInConsole: false))); logsInConsole: true),
api: VeilidWASMConfigLoggingApi(
enabled: true, level: VeilidConfigLogLevel.info)));
Veilid.instance.configureVeilidPlatform(platformConfig.json); Veilid.instance.configureVeilidPlatform(platformConfig.json);
} else { } else {
var platformConfig = VeilidFFIConfig( var platformConfig = VeilidFFIConfig(
logging: VeilidFFIConfigLogging( logging: VeilidFFIConfigLogging(
terminal: VeilidFFIConfigLoggingTerminal( terminal: VeilidFFIConfigLoggingTerminal(
enabled: false, enabled: false,
level: VeilidLogLevel.trace, level: VeilidConfigLogLevel.debug,
), ),
otlp: VeilidFFIConfigLoggingOtlp( otlp: VeilidFFIConfigLoggingOtlp(
enabled: false, enabled: false,
level: VeilidLogLevel.trace, level: VeilidConfigLogLevel.trace,
grpcEndpoint: "localhost:4317", grpcEndpoint: "localhost:4317",
serviceName: "VeilidExample"))); serviceName: "VeilidExample"),
api: VeilidFFIConfigLoggingApi(
enabled: true, level: VeilidConfigLogLevel.info)));
Veilid.instance.configureVeilidPlatform(platformConfig.json); Veilid.instance.configureVeilidPlatform(platformConfig.json);
} }

View File

@ -13,7 +13,7 @@ import 'veilid_stub.dart'
class VeilidFFIConfigLoggingTerminal { class VeilidFFIConfigLoggingTerminal {
bool enabled; bool enabled;
VeilidLogLevel level; VeilidConfigLogLevel level;
VeilidFFIConfigLoggingTerminal({ VeilidFFIConfigLoggingTerminal({
required this.enabled, required this.enabled,
@ -29,12 +29,12 @@ class VeilidFFIConfigLoggingTerminal {
VeilidFFIConfigLoggingTerminal.fromJson(Map<String, dynamic> json) VeilidFFIConfigLoggingTerminal.fromJson(Map<String, dynamic> json)
: enabled = json['enabled'], : enabled = json['enabled'],
level = veilidLogLevelFromJson(json['level']); level = veilidConfigLogLevelFromJson(json['level']);
} }
class VeilidFFIConfigLoggingOtlp { class VeilidFFIConfigLoggingOtlp {
bool enabled; bool enabled;
VeilidLogLevel level; VeilidConfigLogLevel level;
String grpcEndpoint; String grpcEndpoint;
String serviceName; String serviceName;
@ -56,27 +56,52 @@ class VeilidFFIConfigLoggingOtlp {
VeilidFFIConfigLoggingOtlp.fromJson(Map<String, dynamic> json) VeilidFFIConfigLoggingOtlp.fromJson(Map<String, dynamic> json)
: enabled = json['enabled'], : enabled = json['enabled'],
level = veilidLogLevelFromJson(json['level']), level = veilidConfigLogLevelFromJson(json['level']),
grpcEndpoint = json['grpc_endpoint'], grpcEndpoint = json['grpc_endpoint'],
serviceName = json['service_name']; serviceName = json['service_name'];
} }
class VeilidFFIConfigLoggingApi {
bool enabled;
VeilidConfigLogLevel level;
VeilidFFIConfigLoggingApi({
required this.enabled,
required this.level,
});
Map<String, dynamic> get json {
return {
'enabled': enabled,
'level': level.json,
};
}
VeilidFFIConfigLoggingApi.fromJson(Map<String, dynamic> json)
: enabled = json['enabled'],
level = veilidConfigLogLevelFromJson(json['level']);
}
class VeilidFFIConfigLogging { class VeilidFFIConfigLogging {
VeilidFFIConfigLoggingTerminal terminal; VeilidFFIConfigLoggingTerminal terminal;
VeilidFFIConfigLoggingOtlp otlp; VeilidFFIConfigLoggingOtlp otlp;
VeilidFFIConfigLoggingApi api;
VeilidFFIConfigLogging({required this.terminal, required this.otlp}); VeilidFFIConfigLogging(
{required this.terminal, required this.otlp, required this.api});
Map<String, dynamic> get json { Map<String, dynamic> get json {
return { return {
'terminal': terminal.json, 'terminal': terminal.json,
'otlp': otlp.json, 'otlp': otlp.json,
'api': api.json,
}; };
} }
VeilidFFIConfigLogging.fromJson(Map<String, dynamic> json) VeilidFFIConfigLogging.fromJson(Map<String, dynamic> json)
: terminal = VeilidFFIConfigLoggingTerminal.fromJson(json['terminal']), : terminal = VeilidFFIConfigLoggingTerminal.fromJson(json['terminal']),
otlp = VeilidFFIConfigLoggingOtlp.fromJson(json['otlp']); otlp = VeilidFFIConfigLoggingOtlp.fromJson(json['otlp']),
api = VeilidFFIConfigLoggingApi.fromJson(json['api']);
} }
class VeilidFFIConfig { class VeilidFFIConfig {
@ -101,7 +126,7 @@ class VeilidFFIConfig {
class VeilidWASMConfigLoggingPerformance { class VeilidWASMConfigLoggingPerformance {
bool enabled; bool enabled;
VeilidLogLevel level; VeilidConfigLogLevel level;
bool logsInTimings; bool logsInTimings;
bool logsInConsole; bool logsInConsole;
@ -123,25 +148,49 @@ class VeilidWASMConfigLoggingPerformance {
VeilidWASMConfigLoggingPerformance.fromJson(Map<String, dynamic> json) VeilidWASMConfigLoggingPerformance.fromJson(Map<String, dynamic> json)
: enabled = json['enabled'], : enabled = json['enabled'],
level = veilidLogLevelFromJson(json['level']), level = veilidConfigLogLevelFromJson(json['level']),
logsInTimings = json['logs_in_timings'], logsInTimings = json['logs_in_timings'],
logsInConsole = json['logs_in_console']; logsInConsole = json['logs_in_console'];
} }
class VeilidWASMConfigLoggingApi {
bool enabled;
VeilidConfigLogLevel level;
VeilidWASMConfigLoggingApi({
required this.enabled,
required this.level,
});
Map<String, dynamic> get json {
return {
'enabled': enabled,
'level': level.json,
};
}
VeilidWASMConfigLoggingApi.fromJson(Map<String, dynamic> json)
: enabled = json['enabled'],
level = veilidConfigLogLevelFromJson(json['level']);
}
class VeilidWASMConfigLogging { class VeilidWASMConfigLogging {
VeilidWASMConfigLoggingPerformance performance; VeilidWASMConfigLoggingPerformance performance;
VeilidWASMConfigLoggingApi api;
VeilidWASMConfigLogging({required this.performance}); VeilidWASMConfigLogging({required this.performance, required this.api});
Map<String, dynamic> get json { Map<String, dynamic> get json {
return { return {
'performance': performance.json, 'performance': performance.json,
'api': api.json,
}; };
} }
VeilidWASMConfigLogging.fromJson(Map<String, dynamic> json) VeilidWASMConfigLogging.fromJson(Map<String, dynamic> json)
: performance = : performance =
VeilidWASMConfigLoggingPerformance.fromJson(json['performance']); VeilidWASMConfigLoggingPerformance.fromJson(json['performance']),
api = VeilidWASMConfigLoggingApi.fromJson(json['api']);
} }
class VeilidWASMConfig { class VeilidWASMConfig {
@ -899,7 +948,6 @@ class VeilidConfigCapabilities {
class VeilidConfig { class VeilidConfig {
String programName; String programName;
String namespace; String namespace;
VeilidConfigLogLevel apiLogLevel;
VeilidConfigCapabilities capabilities; VeilidConfigCapabilities capabilities;
VeilidConfigProtectedStore protectedStore; VeilidConfigProtectedStore protectedStore;
VeilidConfigTableStore tableStore; VeilidConfigTableStore tableStore;
@ -909,7 +957,6 @@ class VeilidConfig {
VeilidConfig({ VeilidConfig({
required this.programName, required this.programName,
required this.namespace, required this.namespace,
required this.apiLogLevel,
required this.capabilities, required this.capabilities,
required this.protectedStore, required this.protectedStore,
required this.tableStore, required this.tableStore,
@ -921,7 +968,6 @@ class VeilidConfig {
return { return {
'program_name': programName, 'program_name': programName,
'namespace': namespace, 'namespace': namespace,
'api_log_level': apiLogLevel.json,
'capabilities': capabilities.json, 'capabilities': capabilities.json,
'protected_store': protectedStore.json, 'protected_store': protectedStore.json,
'table_store': tableStore.json, 'table_store': tableStore.json,
@ -933,7 +979,6 @@ class VeilidConfig {
VeilidConfig.fromJson(Map<String, dynamic> json) VeilidConfig.fromJson(Map<String, dynamic> json)
: programName = json['program_name'], : programName = json['program_name'],
namespace = json['namespace'], namespace = json['namespace'],
apiLogLevel = json['api_log_level'],
capabilities = VeilidConfigCapabilities.fromJson(json['capabilities']), capabilities = VeilidConfigCapabilities.fromJson(json['capabilities']),
protectedStore = protectedStore =
VeilidConfigProtectedStore.fromJson(json['protected_store']), VeilidConfigProtectedStore.fromJson(json['protected_store']),
@ -1253,9 +1298,9 @@ abstract class Veilid {
static late Veilid instance = getVeilid(); static late Veilid instance = getVeilid();
void configureVeilidPlatform(Map<String, dynamic> platformConfigJson); void configureVeilidPlatform(Map<String, dynamic> platformConfigJson);
void changeLogLevel(String layer, VeilidConfigLogLevel logLevel);
Stream<VeilidUpdate> startupVeilidCore(VeilidConfig config); Stream<VeilidUpdate> startupVeilidCore(VeilidConfig config);
Future<VeilidState> getVeilidState(); Future<VeilidState> getVeilidState();
Future<void> changeApiLogLevel(VeilidConfigLogLevel logLevel);
Future<void> shutdownVeilidCore(); Future<void> shutdownVeilidCore();
Future<String> debug(String command); Future<String> debug(String command);
String veilidVersionString(); String veilidVersionString();

View File

@ -32,15 +32,15 @@ typedef _InitializeVeilidFlutterDart = void Function(Pointer<_DartPostCObject>);
// fn configure_veilid_platform(platform_config: FfiStr) // fn configure_veilid_platform(platform_config: FfiStr)
typedef _ConfigureVeilidPlatformC = Void Function(Pointer<Utf8>); typedef _ConfigureVeilidPlatformC = Void Function(Pointer<Utf8>);
typedef _ConfigureVeilidPlatformDart = void Function(Pointer<Utf8>); typedef _ConfigureVeilidPlatformDart = void Function(Pointer<Utf8>);
// fn change_log_level(layer: FfiStr, log_level: FfiStr)
typedef _ChangeLogLevelC = Void Function(Pointer<Utf8>, Pointer<Utf8>);
typedef _ChangeLogLevelDart = void Function(Pointer<Utf8>, Pointer<Utf8>);
// fn startup_veilid_core(port: i64, config: FfiStr) // fn startup_veilid_core(port: i64, config: FfiStr)
typedef _StartupVeilidCoreC = Void Function(Int64, Pointer<Utf8>); typedef _StartupVeilidCoreC = Void Function(Int64, Pointer<Utf8>);
typedef _StartupVeilidCoreDart = void Function(int, Pointer<Utf8>); typedef _StartupVeilidCoreDart = void Function(int, Pointer<Utf8>);
// fn get_veilid_state(port: i64) // fn get_veilid_state(port: i64)
typedef _GetVeilidStateC = Void Function(Int64); typedef _GetVeilidStateC = Void Function(Int64);
typedef _GetVeilidStateDart = void Function(int); typedef _GetVeilidStateDart = void Function(int);
// fn change_api_log_level(port: i64, log_level: FfiStr)
typedef _ChangeApiLogLevelC = Void Function(Int64, Pointer<Utf8>);
typedef _ChangeApiLogLevelDart = void Function(int, Pointer<Utf8>);
// fn debug(port: i64, log_level: FfiStr) // fn debug(port: i64, log_level: FfiStr)
typedef _DebugC = Void Function(Int64, Pointer<Utf8>); typedef _DebugC = Void Function(Int64, Pointer<Utf8>);
typedef _DebugDart = void Function(int, Pointer<Utf8>); typedef _DebugDart = void Function(int, Pointer<Utf8>);
@ -246,9 +246,9 @@ class VeilidFFI implements Veilid {
// Shared library functions // Shared library functions
final _FreeStringDart _freeString; final _FreeStringDart _freeString;
final _ConfigureVeilidPlatformDart _configureVeilidPlatform; final _ConfigureVeilidPlatformDart _configureVeilidPlatform;
final _ChangeLogLevelDart _changeLogLevel;
final _StartupVeilidCoreDart _startupVeilidCore; final _StartupVeilidCoreDart _startupVeilidCore;
final _GetVeilidStateDart _getVeilidState; final _GetVeilidStateDart _getVeilidState;
final _ChangeApiLogLevelDart _changeApiLogLevel;
final _ShutdownVeilidCoreDart _shutdownVeilidCore; final _ShutdownVeilidCoreDart _shutdownVeilidCore;
final _DebugDart _debug; final _DebugDart _debug;
final _VeilidVersionStringDart _veilidVersionString; final _VeilidVersionStringDart _veilidVersionString;
@ -261,15 +261,15 @@ class VeilidFFI implements Veilid {
_configureVeilidPlatform = dylib.lookupFunction< _configureVeilidPlatform = dylib.lookupFunction<
_ConfigureVeilidPlatformC, _ConfigureVeilidPlatformC,
_ConfigureVeilidPlatformDart>('configure_veilid_platform'), _ConfigureVeilidPlatformDart>('configure_veilid_platform'),
_changeLogLevel =
dylib.lookupFunction<_ChangeLogLevelC, _ChangeLogLevelDart>(
'change_log_level'),
_startupVeilidCore = _startupVeilidCore =
dylib.lookupFunction<_StartupVeilidCoreC, _StartupVeilidCoreDart>( dylib.lookupFunction<_StartupVeilidCoreC, _StartupVeilidCoreDart>(
'startup_veilid_core'), 'startup_veilid_core'),
_getVeilidState = _getVeilidState =
dylib.lookupFunction<_GetVeilidStateC, _GetVeilidStateDart>( dylib.lookupFunction<_GetVeilidStateC, _GetVeilidStateDart>(
'get_veilid_state'), 'get_veilid_state'),
_changeApiLogLevel =
dylib.lookupFunction<_ChangeApiLogLevelC, _ChangeApiLogLevelDart>(
'change_api_log_level'),
_shutdownVeilidCore = _shutdownVeilidCore =
dylib.lookupFunction<_ShutdownVeilidCoreC, _ShutdownVeilidCoreDart>( dylib.lookupFunction<_ShutdownVeilidCoreC, _ShutdownVeilidCoreDart>(
'shutdown_veilid_core'), 'shutdown_veilid_core'),
@ -297,6 +297,17 @@ class VeilidFFI implements Veilid {
malloc.free(nativePlatformConfig); malloc.free(nativePlatformConfig);
} }
@override
void changeLogLevel(String layer, VeilidConfigLogLevel logLevel) {
var nativeLogLevel =
jsonEncode(logLevel.json, toEncodable: veilidApiToEncodable)
.toNativeUtf8();
var nativeLayer = layer.toNativeUtf8();
_changeLogLevel(nativeLayer, nativeLogLevel);
malloc.free(nativeLayer);
malloc.free(nativeLogLevel);
}
@override @override
Stream<VeilidUpdate> startupVeilidCore(VeilidConfig config) { Stream<VeilidUpdate> startupVeilidCore(VeilidConfig config) {
var nativeConfig = var nativeConfig =
@ -317,18 +328,6 @@ class VeilidFFI implements Veilid {
return processFutureJson(VeilidState.fromJson, recvPort.first); return processFutureJson(VeilidState.fromJson, recvPort.first);
} }
@override
Future<void> changeApiLogLevel(VeilidConfigLogLevel logLevel) async {
var nativeLogLevel =
jsonEncode(logLevel.json, toEncodable: veilidApiToEncodable)
.toNativeUtf8();
final recvPort = ReceivePort("change_api_log_level");
final sendPort = recvPort.sendPort;
_changeApiLogLevel(sendPort.nativePort, nativeLogLevel);
malloc.free(nativeLogLevel);
return processFutureVoid(recvPort.first);
}
@override @override
Future<void> shutdownVeilidCore() async { Future<void> shutdownVeilidCore() async {
final recvPort = ReceivePort("shutdown_veilid_core"); final recvPort = ReceivePort("shutdown_veilid_core");

View File

@ -27,6 +27,13 @@ class VeilidJS implements Veilid {
wasm, "configure_veilid_platform", [platformConfigJsonString]); wasm, "configure_veilid_platform", [platformConfigJsonString]);
} }
@override
void changeLogLevel(String layer, VeilidConfigLogLevel logLevel) {
var logLevelJsonString =
jsonEncode(logLevel.json, toEncodable: veilidApiToEncodable);
js_util.callMethod(wasm, "change_log_level", [layer, logLevelJsonString]);
}
@override @override
Stream<VeilidUpdate> startupVeilidCore(VeilidConfig config) async* { Stream<VeilidUpdate> startupVeilidCore(VeilidConfig config) async* {
var streamController = StreamController<VeilidUpdate>(); var streamController = StreamController<VeilidUpdate>();
@ -53,12 +60,6 @@ class VeilidJS implements Veilid {
js_util.callMethod(wasm, "get_veilid_state", [])))); js_util.callMethod(wasm, "get_veilid_state", []))));
} }
@override
Future<void> changeApiLogLevel(VeilidConfigLogLevel logLevel) {
return _wrapApiPromise(js_util.callMethod(wasm, "change_api_log_level",
[jsonEncode(logLevel.json, toEncodable: veilidApiToEncodable)]));
}
@override @override
Future<void> shutdownVeilidCore() { Future<void> shutdownVeilidCore() {
return _wrapApiPromise( return _wrapApiPromise(

View File

@ -7,7 +7,9 @@ use lazy_static::*;
use opentelemetry::sdk::*; use opentelemetry::sdk::*;
use opentelemetry::*; use opentelemetry::*;
use opentelemetry_otlp::WithExportConfig; use opentelemetry_otlp::WithExportConfig;
use parking_lot::Mutex;
use serde::*; use serde::*;
use std::collections::BTreeMap;
use std::os::raw::c_char; use std::os::raw::c_char;
use std::sync::Arc; use std::sync::Arc;
use tracing::*; use tracing::*;
@ -15,9 +17,10 @@ use tracing_subscriber::prelude::*;
use tracing_subscriber::*; use tracing_subscriber::*;
// Globals // Globals
lazy_static! { lazy_static! {
static ref VEILID_API: AsyncMutex<Option<veilid_core::VeilidAPI>> = AsyncMutex::new(None); static ref VEILID_API: AsyncMutex<Option<veilid_core::VeilidAPI>> = AsyncMutex::new(None);
static ref FILTERS: Mutex<BTreeMap<&'static str, veilid_core::VeilidLayerFilter>> =
Mutex::new(BTreeMap::new());
} }
async fn get_veilid_api() -> Result<veilid_core::VeilidAPI, veilid_core::VeilidAPIError> { async fn get_veilid_api() -> Result<veilid_core::VeilidAPI, veilid_core::VeilidAPIError> {
@ -35,17 +38,6 @@ async fn take_veilid_api() -> Result<veilid_core::VeilidAPI, veilid_core::Veilid
.ok_or(veilid_core::VeilidAPIError::NotInitialized) .ok_or(veilid_core::VeilidAPIError::NotInitialized)
} }
fn logfilter<T: AsRef<str>, V: AsRef<[T]>>(metadata: &Metadata, ignore_list: V) -> bool {
// Skip filtered targets
!match (metadata.target(), ignore_list.as_ref()) {
(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.as_ref()))
}
_ => false,
}
}
///////////////////////////////////////// /////////////////////////////////////////
// FFI Helpers // FFI Helpers
@ -75,21 +67,28 @@ macro_rules! check_err_json {
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub struct VeilidFFIConfigLoggingTerminal { pub struct VeilidFFIConfigLoggingTerminal {
pub enabled: bool, pub enabled: bool,
pub level: veilid_core::VeilidLogLevel, pub level: veilid_core::VeilidConfigLogLevel,
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub struct VeilidFFIConfigLoggingOtlp { pub struct VeilidFFIConfigLoggingOtlp {
pub enabled: bool, pub enabled: bool,
pub level: veilid_core::VeilidLogLevel, pub level: veilid_core::VeilidConfigLogLevel,
pub grpc_endpoint: String, pub grpc_endpoint: String,
pub service_name: String, pub service_name: String,
} }
#[derive(Debug, Deserialize, Serialize)]
pub struct VeilidFFIConfigLoggingApi {
pub enabled: bool,
pub level: veilid_core::VeilidConfigLogLevel,
}
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub struct VeilidFFIConfigLogging { pub struct VeilidFFIConfigLogging {
pub terminal: VeilidFFIConfigLoggingTerminal, pub terminal: VeilidFFIConfigLoggingTerminal,
pub otlp: VeilidFFIConfigLoggingOtlp, pub otlp: VeilidFFIConfigLoggingOtlp,
pub api: VeilidFFIConfigLoggingApi,
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
@ -149,40 +148,24 @@ pub extern "C" fn configure_veilid_platform(platform_config: FfiStr) {
.expect("failed to deserialize plaform config json"); .expect("failed to deserialize plaform config json");
// Set up subscriber and layers // Set up subscriber and layers
let mut ignore_list = Vec::<String>::new();
for ig in veilid_core::DEFAULT_LOG_IGNORE_LIST {
ignore_list.push(ig.to_owned());
}
let subscriber = Registry::default(); let subscriber = Registry::default();
let mut layers = Vec::new();
let mut filters = (*FILTERS).lock();
// Terminal logger // Terminal logger
let subscriber = subscriber.with(if platform_config.logging.terminal.enabled { if platform_config.logging.terminal.enabled {
let terminal_max_log_level: level_filters::LevelFilter = platform_config let filter =
.logging veilid_core::VeilidLayerFilter::new(platform_config.logging.terminal.level, None);
.terminal let layer = fmt::Layer::new()
.level .compact()
.to_tracing_level() .with_writer(std::io::stdout)
.into(); .with_filter(filter.clone());
filters.insert("terminal", filter);
let ignore_list = ignore_list.clone(); layers.push(layer.boxed());
Some( };
fmt::Layer::new()
.compact()
.with_writer(std::io::stdout)
.with_filter(terminal_max_log_level)
.with_filter(filter::FilterFn::new(move |metadata| {
logfilter(metadata, &ignore_list)
})),
)
} else {
None
});
// OpenTelemetry logger // OpenTelemetry logger
let subscriber = subscriber.with(if platform_config.logging.otlp.enabled { if platform_config.logging.otlp.enabled {
let otlp_max_log_level: level_filters::LevelFilter =
platform_config.logging.otlp.level.to_tracing_level().into();
let grpc_endpoint = platform_config.logging.otlp.grpc_endpoint.clone(); let grpc_endpoint = platform_config.logging.otlp.grpc_endpoint.clone();
cfg_if! { cfg_if! {
@ -218,21 +201,23 @@ pub extern "C" fn configure_veilid_platform(platform_config: FfiStr) {
.map_err(|e| format!("failed to install OpenTelemetry tracer: {}", e)) .map_err(|e| format!("failed to install OpenTelemetry tracer: {}", e))
.unwrap(); .unwrap();
let ignore_list = ignore_list.clone(); let filter = veilid_core::VeilidLayerFilter::new(platform_config.logging.otlp.level, None);
Some( let layer = tracing_opentelemetry::layer()
tracing_opentelemetry::layer() .with_tracer(tracer)
.with_tracer(tracer) .with_filter(filter.clone());
.with_filter(otlp_max_log_level) filters.insert("otlp", filter);
.with_filter(filter::FilterFn::new(move |metadata| { layers.push(layer.boxed());
logfilter(metadata, &ignore_list) }
})),
)
} else {
None
});
// API logger (always add layer, startup will init this if it is enabled in settings) // API logger
let subscriber = subscriber.with(veilid_core::ApiTracingLayer::get()); if platform_config.logging.api.enabled {
let filter = veilid_core::VeilidLayerFilter::new(platform_config.logging.api.level, None);
let layer = veilid_core::ApiTracingLayer::get().with_filter(filter.clone());
filters.insert("api", filter);
layers.push(layer.boxed());
}
let subscriber = subscriber.with(layers);
subscriber subscriber
.try_init() .try_init()
@ -240,6 +225,32 @@ pub extern "C" fn configure_veilid_platform(platform_config: FfiStr) {
.expect("failed to initalize ffi platform"); .expect("failed to initalize ffi platform");
} }
#[no_mangle]
#[instrument(level = "debug")]
pub extern "C" fn change_log_level(layer: FfiStr, log_level: FfiStr) {
// get layer to change level on
let layer = layer.into_opt_string().unwrap_or("all".to_owned());
let layer = if layer == "all" { "".to_owned() } else { layer };
// get log level to change layer to
let log_level = log_level.into_opt_string();
let log_level: veilid_core::VeilidConfigLogLevel =
veilid_core::deserialize_opt_json(log_level).unwrap();
// change log level on appropriate layer
let filters = (*FILTERS).lock();
if layer.is_empty() {
// Change all layers
for f in filters.values() {
f.set_max_level(log_level);
}
} else {
// Change a specific layer
let f = filters.get(layer.as_str()).unwrap();
f.set_max_level(log_level);
}
}
#[no_mangle] #[no_mangle]
#[instrument] #[instrument]
pub extern "C" fn startup_veilid_core(port: i64, config: FfiStr) { pub extern "C" fn startup_veilid_core(port: i64, config: FfiStr) {
@ -291,20 +302,6 @@ pub extern "C" fn get_veilid_state(port: i64) {
}); });
} }
#[no_mangle]
#[instrument(level = "debug")]
pub extern "C" fn change_api_log_level(port: i64, log_level: FfiStr) {
let log_level = log_level.into_opt_string();
DartIsolateWrapper::new(port).spawn_result_json(async move {
let log_level: veilid_core::VeilidConfigLogLevel =
veilid_core::deserialize_opt_json(log_level)?;
//let veilid_api = get_veilid_api().await?;
//veilid_api.change_api_log_level(log_level).await;
veilid_core::ApiTracingLayer::change_api_log_level(log_level.to_veilid_log_level());
APIRESULT_VOID
});
}
#[no_mangle] #[no_mangle]
#[instrument] #[instrument]
pub extern "C" fn shutdown_veilid_core(port: i64) { pub extern "C" fn shutdown_veilid_core(port: i64) {

View File

@ -36,7 +36,6 @@ capnp = "^0"
parking_lot = "^0" parking_lot = "^0"
capnp-rpc = "^0" capnp-rpc = "^0"
config = { version = "^0", features = ["yaml"] } config = { version = "^0", features = ["yaml"] }
failure = "^0"
cfg-if = "^1" cfg-if = "^1"
serde = "^1" serde = "^1"
serde_derive = "^1" serde_derive = "^1"

View File

@ -1,20 +1,24 @@
@0xd29582d26b2fb073; @0xd29582d26b2fb073;
struct ApiResult {
union {
ok @0 :Text;
err @1 :Text;
}
}
interface Registration {} interface Registration {}
interface VeilidServer { interface VeilidServer {
register @0 (veilidClient: VeilidClient) -> (registration: Registration, state: Text); register @0 (veilidClient: VeilidClient) -> (registration: Registration, state: Text);
debug @1 (what: Text) -> (output: Text); debug @1 (command: Text) -> (result :ApiResult);
attach @2 () -> (result :ApiResult);
attach @2 (); detach @3 () -> (result :ApiResult);
detach @3 ();
shutdown @4 (); shutdown @4 ();
getState @5 () -> (state: Text); getState @5 () -> (result :ApiResult);
changeLogLevel @6 (layer: Text, logLevel: Text) -> (result :ApiResult);
} }
interface VeilidClient { interface VeilidClient {
update @0 (veilidUpdate: Text); update @0 (veilidUpdate: Text);
} }

View File

@ -1,12 +1,14 @@
use crate::tools::*; use crate::tools::*;
use crate::veilid_client_capnp::*; use crate::veilid_client_capnp::*;
use crate::veilid_logs::VeilidLogs;
use capnp::capability::Promise; use capnp::capability::Promise;
use capnp_rpc::{pry, rpc_twoparty_capnp, twoparty, RpcSystem}; use capnp_rpc::{pry, rpc_twoparty_capnp, twoparty, RpcSystem};
use cfg_if::*; use cfg_if::*;
use failure::*;
use futures_util::{future::try_join_all, FutureExt as FuturesFutureExt, StreamExt}; use futures_util::{future::try_join_all, FutureExt as FuturesFutureExt, StreamExt};
use serde::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::rc::Rc; use std::rc::Rc;
use stop_token::future::FutureExt; use stop_token::future::FutureExt;
@ -14,9 +16,20 @@ use stop_token::*;
use tracing::*; use tracing::*;
use veilid_core::*; use veilid_core::*;
#[derive(Fail, Debug)] // Encoding for ApiResult
#[fail(display = "Client API error: {}", _0)] fn encode_api_result<T: Serialize + fmt::Debug>(
pub struct ClientAPIError(String); result: &Result<T, VeilidAPIError>,
builder: &mut api_result::Builder,
) {
match result {
Ok(v) => {
builder.set_ok(&serialize_json(v));
}
Err(e) => {
builder.set_err(&serialize_json(e));
}
}
}
// --- interface Registration --------------------------------- // --- interface Registration ---------------------------------
@ -67,17 +80,19 @@ impl registration::Server for RegistrationImpl {}
struct VeilidServerImpl { struct VeilidServerImpl {
veilid_api: veilid_core::VeilidAPI, veilid_api: veilid_core::VeilidAPI,
veilid_logs: VeilidLogs,
next_id: u64, next_id: u64,
pub registration_map: Rc<RefCell<RegistrationMap>>, pub registration_map: Rc<RefCell<RegistrationMap>>,
} }
impl VeilidServerImpl { impl VeilidServerImpl {
#[instrument(level = "trace", skip_all)] #[instrument(level = "trace", skip_all)]
pub fn new(veilid_api: veilid_core::VeilidAPI) -> Self { pub fn new(veilid_api: veilid_core::VeilidAPI, veilid_logs: VeilidLogs) -> Self {
Self { Self {
next_id: 0, next_id: 0,
registration_map: Rc::new(RefCell::new(RegistrationMap::new())), registration_map: Rc::new(RefCell::new(RegistrationMap::new())),
veilid_api, veilid_api,
veilid_logs,
} }
} }
} }
@ -115,13 +130,7 @@ impl veilid_server::Server for VeilidServerImpl {
let mut res = results.get(); let mut res = results.get();
res.set_registration(registration); res.set_registration(registration);
let mut rpc_state = res.init_state( res.set_state(&state);
state
.len()
.try_into()
.map_err(|e| ::capnp::Error::failed(format!("{:?}", e)))?,
);
rpc_state.push_str(&state);
Ok(()) Ok(())
}) })
@ -135,14 +144,11 @@ impl veilid_server::Server for VeilidServerImpl {
) -> Promise<(), ::capnp::Error> { ) -> Promise<(), ::capnp::Error> {
trace!("VeilidServerImpl::debug"); trace!("VeilidServerImpl::debug");
let veilid_api = self.veilid_api.clone(); let veilid_api = self.veilid_api.clone();
let what = pry!(pry!(params.get()).get_what()).to_owned(); let command = pry!(pry!(params.get()).get_command()).to_owned();
Promise::from_future(async move { Promise::from_future(async move {
let output = veilid_api let result = veilid_api.debug(command).await;
.debug(what) encode_api_result(&result, &mut results.get().init_result());
.await
.map_err(|e| ::capnp::Error::failed(format!("{:?}", e)))?;
results.get().set_output(output.as_str());
Ok(()) Ok(())
}) })
} }
@ -151,15 +157,14 @@ impl veilid_server::Server for VeilidServerImpl {
fn attach( fn attach(
&mut self, &mut self,
_params: veilid_server::AttachParams, _params: veilid_server::AttachParams,
mut _results: veilid_server::AttachResults, mut results: veilid_server::AttachResults,
) -> Promise<(), ::capnp::Error> { ) -> Promise<(), ::capnp::Error> {
trace!("VeilidServerImpl::attach"); trace!("VeilidServerImpl::attach");
let veilid_api = self.veilid_api.clone(); let veilid_api = self.veilid_api.clone();
Promise::from_future(async move { Promise::from_future(async move {
veilid_api let result = veilid_api.attach().await;
.attach() encode_api_result(&result, &mut results.get().init_result());
.await Ok(())
.map_err(|e| ::capnp::Error::failed(format!("{:?}", e)))
}) })
} }
@ -167,15 +172,14 @@ impl veilid_server::Server for VeilidServerImpl {
fn detach( fn detach(
&mut self, &mut self,
_params: veilid_server::DetachParams, _params: veilid_server::DetachParams,
mut _results: veilid_server::DetachResults, mut results: veilid_server::DetachResults,
) -> Promise<(), ::capnp::Error> { ) -> Promise<(), ::capnp::Error> {
trace!("VeilidServerImpl::detach"); trace!("VeilidServerImpl::detach");
let veilid_api = self.veilid_api.clone(); let veilid_api = self.veilid_api.clone();
Promise::from_future(async move { Promise::from_future(async move {
veilid_api let result = veilid_api.detach().await;
.detach() encode_api_result(&result, &mut results.get().init_result());
.await Ok(())
.map_err(|e| ::capnp::Error::failed(format!("{:?}", e)))
}) })
} }
@ -208,24 +212,30 @@ impl veilid_server::Server for VeilidServerImpl {
trace!("VeilidServerImpl::get_state"); trace!("VeilidServerImpl::get_state");
let veilid_api = self.veilid_api.clone(); let veilid_api = self.veilid_api.clone();
Promise::from_future(async move { Promise::from_future(async move {
let state = veilid_api let result = veilid_api.get_state().await;
.get_state() encode_api_result(&result, &mut results.get().init_result());
.await
.map_err(|e| ::capnp::Error::failed(format!("{:?}", e)))?;
let state = serialize_json(state);
let res = results.get();
let mut rpc_state = res.init_state(
state
.len()
.try_into()
.map_err(|e| ::capnp::Error::failed(format!("{:?}", e)))?,
);
rpc_state.push_str(&state);
Ok(()) Ok(())
}) })
} }
#[instrument(level = "trace", skip_all)]
fn change_log_level(
&mut self,
params: veilid_server::ChangeLogLevelParams,
mut results: veilid_server::ChangeLogLevelResults,
) -> Promise<(), ::capnp::Error> {
trace!("VeilidServerImpl::change_log_level");
let layer = pry!(pry!(params.get()).get_layer()).to_owned();
let log_level_json = pry!(pry!(params.get()).get_log_level()).to_owned();
let log_level: veilid_core::VeilidConfigLogLevel =
pry!(veilid_core::deserialize_json(&log_level_json)
.map_err(|e| ::capnp::Error::failed(format!("{:?}", e))));
let result = self.veilid_logs.change_log_level(layer, log_level);
encode_api_result(&result, &mut results.get().init_result());
Promise::ok(())
}
} }
// --- Client API Server-Side --------------------------------- // --- Client API Server-Side ---------------------------------
@ -235,6 +245,7 @@ type ClientApiAllFuturesJoinHandle =
struct ClientApiInner { struct ClientApiInner {
veilid_api: veilid_core::VeilidAPI, veilid_api: veilid_core::VeilidAPI,
veilid_logs: VeilidLogs,
registration_map: Rc<RefCell<RegistrationMap>>, registration_map: Rc<RefCell<RegistrationMap>>,
stop: Option<StopSource>, stop: Option<StopSource>,
join_handle: Option<ClientApiAllFuturesJoinHandle>, join_handle: Option<ClientApiAllFuturesJoinHandle>,
@ -246,10 +257,11 @@ pub struct ClientApi {
impl ClientApi { impl ClientApi {
#[instrument(level = "trace", skip_all)] #[instrument(level = "trace", skip_all)]
pub fn new(veilid_api: veilid_core::VeilidAPI) -> Rc<Self> { pub fn new(veilid_api: veilid_core::VeilidAPI, veilid_logs: VeilidLogs) -> Rc<Self> {
Rc::new(Self { Rc::new(Self {
inner: RefCell::new(ClientApiInner { inner: RefCell::new(ClientApiInner {
veilid_api, veilid_api,
veilid_logs,
registration_map: Rc::new(RefCell::new(RegistrationMap::new())), registration_map: Rc::new(RefCell::new(RegistrationMap::new())),
stop: Some(StopSource::new()), stop: Some(StopSource::new()),
join_handle: None, join_handle: None,
@ -393,7 +405,10 @@ impl ClientApi {
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
pub fn run(self: Rc<Self>, bind_addrs: Vec<SocketAddr>) { pub fn run(self: Rc<Self>, bind_addrs: Vec<SocketAddr>) {
// Create client api VeilidServer // Create client api VeilidServer
let veilid_server_impl = VeilidServerImpl::new(self.inner.borrow().veilid_api.clone()); let veilid_server_impl = VeilidServerImpl::new(
self.inner.borrow().veilid_api.clone(),
self.inner.borrow().veilid_logs.clone(),
);
self.inner.borrow_mut().registration_map = veilid_server_impl.registration_map.clone(); self.inner.borrow_mut().registration_map = veilid_server_impl.registration_map.clone();
// Make a client object for the server to send to each rpc client // Make a client object for the server to send to each rpc client

View File

@ -62,9 +62,9 @@ fn main() -> Result<(), String> {
// run the server to set the node id and quit // run the server to set the node id and quit
return block_on(async { return block_on(async {
// Init combined console/file logger // Init combined console/file logger
let _logs = VeilidLogs::setup(settings.clone())?; let veilid_logs = VeilidLogs::setup(settings.clone())?;
run_veilid_server(settings, server_mode).await run_veilid_server(settings, server_mode, veilid_logs).await
}) })
.map(|v| { .map(|v| {
println!("{}", success); println!("{}", success);
@ -96,8 +96,8 @@ fn main() -> Result<(), String> {
// Run the server loop // Run the server loop
block_on(async { block_on(async {
// Init combined console/file logger // Init combined console/file logger
let _logs = VeilidLogs::setup(settings.clone())?; let veilid_logs = VeilidLogs::setup(settings.clone())?;
run_veilid_server(settings, server_mode).await run_veilid_server(settings, server_mode, veilid_logs).await
}) })
} }

View File

@ -1,6 +1,7 @@
use crate::client_api; use crate::client_api;
use crate::settings::*; use crate::settings::*;
use crate::tools::*; use crate::tools::*;
use crate::veilid_logs::*;
use flume::{unbounded, Receiver, Sender}; use flume::{unbounded, Receiver, Sender};
use lazy_static::*; use lazy_static::*;
use parking_lot::Mutex; use parking_lot::Mutex;
@ -29,14 +30,19 @@ pub fn shutdown() {
} }
} }
pub async fn run_veilid_server(settings: Settings, server_mode: ServerMode) -> Result<(), String> { pub async fn run_veilid_server(
run_veilid_server_internal(settings, server_mode).await settings: Settings,
server_mode: ServerMode,
veilid_logs: VeilidLogs,
) -> Result<(), String> {
run_veilid_server_internal(settings, server_mode, veilid_logs).await
} }
#[instrument(err, skip_all)] #[instrument(err, skip_all)]
pub async fn run_veilid_server_internal( pub async fn run_veilid_server_internal(
settings: Settings, settings: Settings,
server_mode: ServerMode, server_mode: ServerMode,
veilid_logs: VeilidLogs,
) -> Result<(), String> { ) -> Result<(), String> {
trace!(?settings, ?server_mode); trace!(?settings, ?server_mode);
@ -63,7 +69,7 @@ pub async fn run_veilid_server_internal(
// Start client api if one is requested // Start client api if one is requested
let mut capi = if settingsr.client_api.enabled && matches!(server_mode, ServerMode::Normal) { let mut capi = if settingsr.client_api.enabled && matches!(server_mode, ServerMode::Normal) {
let some_capi = client_api::ClientApi::new(veilid_api.clone()); let some_capi = client_api::ClientApi::new(veilid_api.clone(), veilid_logs.clone());
some_capi some_capi
.clone() .clone()
.run(settingsr.client_api.listen_address.addrs.clone()); .run(settingsr.client_api.listen_address.addrs.clone());
@ -156,5 +162,9 @@ pub async fn run_veilid_server_internal(
// Wait for update receiver to exit // Wait for update receiver to exit
let _ = update_receiver_jh.await; let _ = update_receiver_jh.await;
// Finally, drop logs
// this is explicit to ensure we don't accidentally drop them too soon via a move
drop(veilid_logs);
out out
} }

View File

@ -192,6 +192,7 @@ pub fn load_config(
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
pub enum LogLevel { pub enum LogLevel {
Off,
Error, Error,
Warn, Warn,
Info, Info,
@ -205,6 +206,7 @@ impl<'de> serde::Deserialize<'de> for LogLevel {
{ {
let s = String::deserialize(deserializer)?; let s = String::deserialize(deserializer)?;
match s.to_ascii_lowercase().as_str() { match s.to_ascii_lowercase().as_str() {
"off" => Ok(LogLevel::Off),
"error" => Ok(LogLevel::Error), "error" => Ok(LogLevel::Error),
"warn" => Ok(LogLevel::Warn), "warn" => Ok(LogLevel::Warn),
"info" => Ok(LogLevel::Info), "info" => Ok(LogLevel::Info),
@ -223,6 +225,7 @@ impl serde::Serialize for LogLevel {
S: serde::Serializer, S: serde::Serializer,
{ {
let s = match self { let s = match self {
LogLevel::Off => "off",
LogLevel::Error => "error", LogLevel::Error => "error",
LogLevel::Warn => "warn", LogLevel::Warn => "warn",
LogLevel::Info => "info", LogLevel::Info => "info",
@ -233,13 +236,14 @@ impl serde::Serialize for LogLevel {
} }
} }
pub fn convert_loglevel(log_level: LogLevel) -> veilid_core::VeilidLogLevel { pub fn convert_loglevel(log_level: LogLevel) -> veilid_core::VeilidConfigLogLevel {
match log_level { match log_level {
LogLevel::Error => veilid_core::VeilidLogLevel::Error, LogLevel::Off => veilid_core::VeilidConfigLogLevel::Off,
LogLevel::Warn => veilid_core::VeilidLogLevel::Warn, LogLevel::Error => veilid_core::VeilidConfigLogLevel::Error,
LogLevel::Info => veilid_core::VeilidLogLevel::Info, LogLevel::Warn => veilid_core::VeilidConfigLogLevel::Warn,
LogLevel::Debug => veilid_core::VeilidLogLevel::Debug, LogLevel::Info => veilid_core::VeilidConfigLogLevel::Info,
LogLevel::Trace => veilid_core::VeilidLogLevel::Trace, LogLevel::Debug => veilid_core::VeilidConfigLogLevel::Debug,
LogLevel::Trace => veilid_core::VeilidConfigLogLevel::Trace,
} }
} }
@ -1016,13 +1020,6 @@ impl Settings {
} else { } else {
format!("subnode{}", inner.testing.subnode_index) format!("subnode{}", inner.testing.subnode_index)
})), })),
"api_log_level" => Ok(Box::new(if inner.logging.api.enabled {
veilid_core::VeilidConfigLogLevel::from_veilid_log_level(Some(
convert_loglevel(inner.logging.api.level),
))
} else {
veilid_core::VeilidConfigLogLevel::Off
})),
"capabilities.protocol_udp" => Ok(Box::new(true)), "capabilities.protocol_udp" => Ok(Box::new(true)),
"capabilities.protocol_connect_tcp" => Ok(Box::new(true)), "capabilities.protocol_connect_tcp" => Ok(Box::new(true)),
"capabilities.protocol_accept_tcp" => Ok(Box::new(true)), "capabilities.protocol_accept_tcp" => Ok(Box::new(true)),

View File

@ -98,7 +98,7 @@ pub fn run_daemon(settings: Settings, _matches: ArgMatches) -> Result<(), String
// Now, run the server // Now, run the server
block_on(async { block_on(async {
// Init combined console/file logger // Init combined console/file logger
let _logs = VeilidLogs::setup(settings.clone())?; let veilid_logs = VeilidLogs::setup(settings.clone())?;
// Daemonize // Daemonize
daemon daemon
@ -112,7 +112,7 @@ pub fn run_daemon(settings: Settings, _matches: ArgMatches) -> Result<(), String
let signals_task = spawn(handle_signals(signals)); let signals_task = spawn(handle_signals(signals));
let res = run_veilid_server(settings, ServerMode::Normal).await; let res = run_veilid_server(settings, ServerMode::Normal, veilid_logs).await;
// Terminate the signal stream. // Terminate the signal stream.
handle.close(); handle.close();

View File

@ -3,25 +3,22 @@ use cfg_if::*;
use opentelemetry::sdk::*; use opentelemetry::sdk::*;
use opentelemetry::*; use opentelemetry::*;
use opentelemetry_otlp::WithExportConfig; use opentelemetry_otlp::WithExportConfig;
use parking_lot::*;
use std::collections::BTreeMap;
use std::path::*; use std::path::*;
use tracing::*; use std::sync::Arc;
use tracing_appender::*; use tracing_appender::*;
use tracing_subscriber::prelude::*; use tracing_subscriber::prelude::*;
use tracing_subscriber::*; use tracing_subscriber::*;
pub struct VeilidLogs { struct VeilidLogsInner {
pub guard: Option<non_blocking::WorkerGuard>, _guard: Option<non_blocking::WorkerGuard>,
filters: BTreeMap<&'static str, veilid_core::VeilidLayerFilter>,
} }
fn logfilter<T: AsRef<str>, V: AsRef<[T]>>(metadata: &Metadata, ignore_list: V) -> bool { #[derive(Clone)]
// Skip filtered targets pub struct VeilidLogs {
!match (metadata.target(), ignore_list.as_ref()) { inner: Arc<Mutex<VeilidLogsInner>>,
(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.as_ref()))
}
_ => false,
}
} }
impl VeilidLogs { impl VeilidLogs {
@ -29,39 +26,26 @@ impl VeilidLogs {
let settingsr = settings.read(); let settingsr = settings.read();
// Set up subscriber and layers // Set up subscriber and layers
let mut ignore_list = Vec::<String>::new();
for ig in veilid_core::DEFAULT_LOG_IGNORE_LIST {
ignore_list.push(ig.to_owned());
}
let subscriber = Registry::default(); let subscriber = Registry::default();
let mut layers = Vec::new();
let mut filters = BTreeMap::new();
// Terminal logger // Terminal logger
let subscriber = subscriber.with(if settingsr.logging.terminal.enabled { if settingsr.logging.terminal.enabled {
let terminal_max_log_level: level_filters::LevelFilter = let filter = veilid_core::VeilidLayerFilter::new(
convert_loglevel(settingsr.logging.terminal.level) convert_loglevel(settingsr.logging.terminal.level),
.to_tracing_level() None,
.into(); );
let ignore_list = ignore_list.clone(); let layer = fmt::Layer::new()
Some( .compact()
fmt::Layer::new() .with_writer(std::io::stdout)
.compact() .with_filter(filter.clone());
.with_writer(std::io::stdout) filters.insert("terminal", filter);
.with_filter(terminal_max_log_level) layers.push(layer.boxed());
.with_filter(filter::FilterFn::new(move |metadata| { }
logfilter(metadata, &ignore_list)
})),
)
} else {
None
});
// OpenTelemetry logger // OpenTelemetry logger
let subscriber = subscriber.with(if settingsr.logging.otlp.enabled { if settingsr.logging.otlp.enabled {
let otlp_max_log_level: level_filters::LevelFilter =
convert_loglevel(settingsr.logging.otlp.level)
.to_tracing_level()
.into();
let grpc_endpoint = settingsr.logging.otlp.grpc_endpoint.name.clone(); let grpc_endpoint = settingsr.logging.otlp.grpc_endpoint.name.clone();
cfg_if! { cfg_if! {
@ -95,27 +79,20 @@ impl VeilidLogs {
.install_batch(batch) .install_batch(batch)
.map_err(|e| format!("failed to install OpenTelemetry tracer: {}", e))?; .map_err(|e| format!("failed to install OpenTelemetry tracer: {}", e))?;
let ignore_list = ignore_list.clone(); let filter = veilid_core::VeilidLayerFilter::new(
Some( convert_loglevel(settingsr.logging.otlp.level),
tracing_opentelemetry::layer() None,
.with_tracer(tracer) );
.with_filter(otlp_max_log_level) let layer = tracing_opentelemetry::layer()
.with_filter(filter::FilterFn::new(move |metadata| { .with_tracer(tracer)
logfilter(metadata, &ignore_list) .with_filter(filter.clone());
})), filters.insert("otlp", filter);
) layers.push(layer.boxed());
} else { }
None
});
// File logger // File logger
let mut guard = None; let mut guard = None;
let subscriber = subscriber.with(if settingsr.logging.file.enabled { if settingsr.logging.file.enabled {
let file_max_log_level: level_filters::LevelFilter =
convert_loglevel(settingsr.logging.file.level)
.to_tracing_level()
.into();
let log_path = Path::new(&settingsr.logging.file.path); let log_path = Path::new(&settingsr.logging.file.path);
let full_path = std::env::current_dir() let full_path = std::env::current_dir()
.unwrap_or(PathBuf::from(MAIN_SEPARATOR.to_string())) .unwrap_or(PathBuf::from(MAIN_SEPARATOR.to_string()))
@ -140,50 +117,88 @@ impl VeilidLogs {
tracing_appender::non_blocking(appender); tracing_appender::non_blocking(appender);
guard = Some(non_blocking_guard); guard = Some(non_blocking_guard);
let ignore_list = ignore_list.clone(); let filter = veilid_core::VeilidLayerFilter::new(
Some( convert_loglevel(settingsr.logging.file.level),
fmt::Layer::new() None,
.compact() );
.with_writer(non_blocking_appender) let layer = fmt::Layer::new()
.with_filter(file_max_log_level) .compact()
.with_filter(filter::FilterFn::new(move |metadata| { .with_writer(non_blocking_appender)
logfilter(metadata, &ignore_list) .with_filter(filter.clone());
})),
) filters.insert("file", filter);
} else { layers.push(layer.boxed());
None }
});
// API logger // API logger
let subscriber = subscriber.with(if settingsr.logging.api.enabled { if settingsr.logging.api.enabled {
// Get layer from veilid core, filtering is done by ApiTracingLayer automatically let filter = veilid_core::VeilidLayerFilter::new(
Some(veilid_core::ApiTracingLayer::get()) convert_loglevel(settingsr.logging.api.level),
} else { None,
None );
}); let layer = veilid_core::ApiTracingLayer::get().with_filter(filter.clone());
filters.insert("api", filter);
layers.push(layer.boxed());
}
// Systemd Journal logger // Systemd Journal logger
cfg_if! { cfg_if! {
if #[cfg(target_os = "linux")] { if #[cfg(target_os = "linux")] {
let subscriber = subscriber.with(if settingsr.logging.system.enabled { if settingsr.logging.system.enabled {
let ignore_list = ignore_list.clone(); let filter = veilid_core::VeilidLayerFilter::new(
let system_max_log_level: level_filters::LevelFilter = convert_loglevel(settingsr.logging.system.level).to_tracing_level().into(); convert_loglevel(settingsr.logging.system.level),
Some(tracing_journald::layer().map_err(|e| format!("failed to set up journald logging: {}", e))? None,
.with_filter(system_max_log_level) );
.with_filter(filter::FilterFn::new(move |metadata| { let layer =tracing_journald::layer().map_err(|e| format!("failed to set up journald logging: {}", e))?
logfilter(metadata, &ignore_list) .with_filter(filter.clone());
})) filters.insert("system", filter);
) layers.push(layer.boxed());
} else { }
None
});
} }
} }
let subscriber = subscriber.with(layers);
subscriber subscriber
.try_init() .try_init()
.map_err(|e| format!("failed to initialize logging: {}", e))?; .map_err(|e| format!("failed to initialize logging: {}", e))?;
Ok(VeilidLogs { guard }) Ok(VeilidLogs {
inner: Arc::new(Mutex::new(VeilidLogsInner {
_guard: guard,
filters,
})),
})
}
pub fn change_log_level(
&self,
layer: String,
log_level: veilid_core::VeilidConfigLogLevel,
) -> Result<(), veilid_core::VeilidAPIError> {
// get layer to change level on
let layer = if layer == "all" { "".to_owned() } else { layer };
// change log level on appropriate layer
let inner = self.inner.lock();
if layer.is_empty() {
// Change all layers
for f in inner.filters.values() {
f.set_max_level(log_level);
}
} else {
// Change a specific layer
let f = match inner.filters.get(layer.as_str()) {
Some(f) => f,
None => {
return Err(veilid_core::VeilidAPIError::InvalidArgument {
context: "change_log_level".to_owned(),
argument: "layer".to_owned(),
value: layer,
});
}
};
f.set_max_level(log_level);
}
Ok(())
} }
} }

View File

@ -32,22 +32,12 @@ pub fn setup() -> () {
SETUP_ONCE.call_once(|| {}); SETUP_ONCE.call_once(|| {});
} }
// Log filtering
fn logfilter<T: AsRef<str>, V: AsRef<[T]>>(metadata: &Metadata, ignore_list: V) -> bool {
// Skip filtered targets
!match (metadata.target(), ignore_list.as_ref()) {
(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.as_ref()))
}
_ => false,
}
}
// API Singleton // API Singleton
lazy_static! { lazy_static! {
static ref VEILID_API: SendWrapper<RefCell<Option<veilid_core::VeilidAPI>>> = static ref VEILID_API: SendWrapper<RefCell<Option<veilid_core::VeilidAPI>>> =
SendWrapper::new(RefCell::new(None)); SendWrapper::new(RefCell::new(None));
static ref FILTERS: SendWrapper<RefCell<BTreeMap<&'static str, veilid_core::VeilidLayerFilter>>> =
SendWrapper::new(RefCell::new(BTreeMap::new()));
} }
fn get_veilid_api() -> Result<veilid_core::VeilidAPI, veilid_core::VeilidAPIError> { fn get_veilid_api() -> Result<veilid_core::VeilidAPI, veilid_core::VeilidAPIError> {
@ -123,9 +113,16 @@ pub struct VeilidWASMConfigLoggingPerformance {
pub logs_in_console: bool, pub logs_in_console: bool,
} }
#[derive(Debug, Deserialize, Serialize)]
pub struct VeilidWASMConfigLoggingAPI {
pub enabled: bool,
pub level: veilid_core::VeilidLogLevel,
}
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub struct VeilidWASMConfigLogging { pub struct VeilidWASMConfigLogging {
pub performance: VeilidWASMConfigLoggingPerformance, pub performance: VeilidWASMConfigLoggingPerformance,
pub api: VeilidWASMConfigLoggingAPI,
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
@ -146,48 +143,61 @@ pub fn configure_veilid_platform(platform_config: String) {
.expect("failed to deserialize plaform config json"); .expect("failed to deserialize plaform config json");
// Set up subscriber and layers // Set up subscriber and layers
let mut ignore_list = Vec::<String>::new();
for ig in veilid_core::DEFAULT_LOG_IGNORE_LIST {
ignore_list.push(ig.to_owned());
}
let subscriber = Registry::default(); let subscriber = Registry::default();
let mut layers = Vec::new();
let handles = (*FILTER_RELOAD_HANDLES).borrow_mut();
// Performance logger // Performance logger
let subscriber = subscriber.with(if platform_config.logging.performance.enabled { if platform_config.logging.performance.enabled {
let performance_max_log_level = let filter =
platform_config.logging.performance.level.to_tracing_level(); veilid_core::VeilidLayerFilter::new(platform_config.logging.performance.level, None);
let layer = WASMLayer::new(
let ignore_list = ignore_list.clone(); WASMLayerConfigBuilder::new()
Some( .set_report_logs_in_timings(platform_config.logging.performance.logs_in_timings)
WASMLayer::new( .set_console_config(if platform_config.logging.performance.logs_in_console {
WASMLayerConfigBuilder::new() ConsoleConfig::ReportWithConsoleColor
.set_report_logs_in_timings(platform_config.logging.performance.logs_in_timings) } else {
.set_console_config(if platform_config.logging.performance.logs_in_console { ConsoleConfig::NoReporting
ConsoleConfig::ReportWithConsoleColor })
} else { .build(),
ConsoleConfig::NoReporting
})
.set_max_level(performance_max_log_level)
.build(),
)
.with_filter(filter::FilterFn::new(move |metadata| {
logfilter(metadata, &ignore_list)
})),
) )
} else { .with_filter(filter.clone());
None handles.insert("performance", filter);
}); layers.push(layer.boxed());
};
// API logger (always add layer, startup will init this if it is enabled in settings) // API logger
let subscriber = subscriber.with(veilid_core::ApiTracingLayer::get()); if platform_config.logging.api.enabled {
let filter = veilid_core::VeilidLayerFilter::new(platform_config.logging.api.level, None);
let layer = veilid_core::ApiTracingLayer::get().with_filter(filter.clone());
handles.insert("api", filter);
layers.push(layer.boxed());
}
let subscriber = subscriber.with(layers);
subscriber subscriber
.try_init() .try_init()
.map_err(|e| format!("failed to initialize logging: {}", e)) .map_err(|e| format!("failed to initialize logging: {}", e))
.expect("failed to initalize WASM platform"); .expect("failed to initalize WASM platform");
} }
#[wasm_bindgen()]
pub fn change_log_level(layer: String, log_level: String) {
let layer = if layer == "all" { "".to_owned() } else { layer };
let log_level: veilid_core::VeilidConfigLogLevel = deserialize_json(&log_level).unwrap();
let filters = (*FILTERS).borrow();
if layer.is_empty() {
// Change all layers
for f in filters.values() {
f.set_max_level(log_level);
}
} else {
// Change a specific layer
let f = filters.get(layer.as_str()).unwrap();
f.set_max_level(log_level);
}
}
#[wasm_bindgen()] #[wasm_bindgen()]
pub fn startup_veilid_core(update_callback: Function, json_config: String) -> Promise { pub fn startup_veilid_core(update_callback: Function, json_config: String) -> Promise {
wrap_api_future(async move { wrap_api_future(async move {
@ -221,17 +231,6 @@ pub fn get_veilid_state() -> Promise {
}) })
} }
#[wasm_bindgen()]
pub fn change_api_log_level(log_level: String) -> Promise {
wrap_api_future(async move {
let log_level: veilid_core::VeilidConfigLogLevel = deserialize_json(&log_level)?;
//let veilid_api = get_veilid_api()?;
//veilid_api.change_api_log_level(log_level).await;
veilid_core::ApiTracingLayer::change_api_log_level(log_level.to_veilid_log_level());
APIRESULT_UNDEFINED
})
}
#[wasm_bindgen()] #[wasm_bindgen()]
pub fn shutdown_veilid_core() -> Promise { pub fn shutdown_veilid_core() -> Promise {
wrap_api_future(async move { wrap_api_future(async move {