>(
cfg_path: Option,
log_level: LevelFilter,
+ module_logging: HashMap,
) -> Result {
let base = RpcContextConfig::load(cfg_path).await?;
let log_epoch = Arc::new(AtomicU64::new(rand::random()));
- let logger =
- EmbassyLogger::init(log_level, log_epoch.clone(), base.log_server.clone(), false);
+ let logger = EmbassyLogger::init(
+ log_level,
+ log_epoch.clone(),
+ base.log_server.clone(),
+ false,
+ module_logging,
+ );
let (shutdown, _) = tokio::sync::broadcast::channel(1);
let secret_store = base.secret_store().await?;
let db = base.db(&secret_store).await?;
diff --git a/appmgr/src/util/logger.rs b/appmgr/src/util/logger.rs
index 58e230568..66d15ba57 100644
--- a/appmgr/src/util/logger.rs
+++ b/appmgr/src/util/logger.rs
@@ -4,8 +4,84 @@ use std::sync::Arc;
use log::{set_boxed_logger, set_max_level, LevelFilter, Metadata, Record};
use reqwest::{Client, Url};
+use sequence_trie::SequenceTrie;
use stderrlog::{StdErrLog, Timestamp};
+#[derive(Clone, Debug)]
+pub struct ModuleMap {
+ trie: SequenceTrie,
+}
+impl ModuleMap {
+ fn new(vals: HashMap) -> Self {
+ let mut module_trie = SequenceTrie::new();
+ for (k, v) in vals {
+ let mut include_submodules = false;
+ let module_key = k
+ .split("::")
+ .take_while(|&s| {
+ if s == "*" {
+ include_submodules = true;
+ false
+ } else {
+ true
+ }
+ })
+ .collect::>();
+ match module_trie.get_node(module_key.clone()) {
+ None => match module_trie.get_ancestor_node(module_key.clone()) {
+ None => {
+ module_trie.insert(module_key, (v, include_submodules));
+ }
+ Some(ancestor) => match ancestor.value() {
+ None => {
+ module_trie.insert(module_key, (v, include_submodules));
+ }
+ Some((_, sub)) => {
+ if !sub {
+ module_trie.insert(module_key, (v, include_submodules));
+ }
+ }
+ },
+ },
+ Some(n) => match n.value() {
+ None => {
+ module_trie.insert(module_key.clone(), (v, include_submodules));
+ if include_submodules {
+ let new_node = module_trie.get_node_mut(module_key).unwrap(); // we just inserted it
+ let child_keys = new_node
+ .children_with_keys()
+ .into_iter()
+ .map(|x| x.0.clone())
+ .collect::>();
+ for c in child_keys {
+ new_node.remove(std::iter::once(&c));
+ }
+ }
+ }
+ Some(_) => unreachable!("Trie build failed on 'impossible' duplicate"),
+ },
+ }
+ }
+ ModuleMap { trie: module_trie }
+ }
+ fn level_for<'a>(&'a self, k: &str) -> &'a LevelFilter {
+ let module_key = k.split("::");
+ match self.trie.get(module_key.clone()) {
+ None => match self.trie.get_ancestor(module_key) {
+ None => &LevelFilter::Off,
+ Some((level_filter, include_submodules)) => {
+ if *include_submodules {
+ level_filter
+ } else {
+ &LevelFilter::Off
+ }
+ }
+ },
+ Some((level_filter, _)) => level_filter,
+ }
+ }
+}
+
#[derive(Clone)]
pub struct EmbassyLogger {
log_level: log::LevelFilter,
@@ -13,6 +89,7 @@ pub struct EmbassyLogger {
logger: StdErrLog,
sharing: Arc,
share_dest: Url,
+ module_map: ModuleMap,
}
impl EmbassyLogger {
pub fn init(
@@ -20,6 +97,7 @@ impl EmbassyLogger {
log_epoch: Arc,
share_dest: Option,
share_errors: bool,
+ module_map: HashMap,
) -> Self {
let share_dest = match share_dest {
None => Url::parse("https://beta-registry-0-3.start9labs.com/error-logs").unwrap(), // TODO
@@ -41,6 +119,7 @@ impl EmbassyLogger {
logger,
sharing: Arc::new(AtomicBool::new(share_errors)),
share_dest: share_dest,
+ module_map: ModuleMap::new(module_map),
};
set_boxed_logger(Box::new(embassy_logger.clone())).unwrap();
set_max_level(log_level);
@@ -53,10 +132,17 @@ impl EmbassyLogger {
impl log::Log for EmbassyLogger {
fn enabled(&self, metadata: &Metadata) -> bool {
- self.logger.enabled(metadata)
+ let top = metadata.target().split("::").next().unwrap();
+ if vec!["embassy", "embassyd", "embassy-cli", "embassy-sdk"].contains(&top) {
+ metadata.level() <= self.log_level
+ } else {
+ &metadata.level() <= self.module_map.level_for(metadata.target())
+ }
}
fn log(&self, record: &Record) {
- self.logger.log(record);
+ if self.enabled(record.metadata()) {
+ self.logger.log(record);
+ }
if self.sharing.load(Ordering::SeqCst) {
if record.level() <= log::Level::Warn {
let mut body = HashMap::new();
@@ -89,3 +175,53 @@ pub async fn order_level() {
pub fn module() {
println!("{}", module_path!())
}
+
+proptest::proptest! {
+ #[test]
+ fn submodules_handled_by_parent(s0 in "[a-z][a-z0-9_]+", s1 in "[a-z][a-z0-9_]+", level in filter_strategy()) {
+ proptest::prop_assume!(level > LevelFilter::Off);
+ let mut hm = HashMap::new();
+ hm.insert(format!("{}::*", s0.clone()), level);
+ let mod_map = ModuleMap::new(hm);
+ proptest::prop_assert_eq!(mod_map.level_for(&format!("{}::{}", s0, s1)), &level)
+ }
+ #[test]
+ fn submodules_ignored_by_parent(s0 in "[a-z][a-z0-9_]+", s1 in "[a-z][a-z0-9_]+", level in filter_strategy()) {
+ proptest::prop_assume!(level > LevelFilter::Off);
+ let mut hm = HashMap::new();
+ hm.insert(s0.clone(), level);
+ let mod_map = ModuleMap::new(hm);
+ proptest::prop_assert_eq!(mod_map.level_for(&format!("{}::{}", s0, s1)), &LevelFilter::Off)
+ }
+ #[test]
+ fn duplicate_insertion_ignored(s0 in "[a-z][a-z0-9_]+", s1 in "[a-z][a-z0-9_]+", level in filter_strategy()) {
+ proptest::prop_assume!(level > LevelFilter::Off);
+ let mut hm = HashMap::new();
+ hm.insert(format!("{}::*", s0.clone()), level);
+ let sub = format!("{}::{}", s0, s1);
+ hm.insert(sub.clone(), level);
+ let mod_map = ModuleMap::new(hm);
+ proptest::prop_assert_eq!(mod_map.trie.get(sub.split("::")), None)
+ }
+ #[test]
+ fn parent_child_simul(s0 in "[a-z][a-z0-9_]+", s1 in "[a-z][a-z0-9_]+", level0 in filter_strategy(), level1 in filter_strategy()) {
+ let mut hm = HashMap::new();
+ hm.insert(s0.clone(), level0);
+ let sub = format!("{}::{}", s0, s1);
+ hm.insert(sub.clone(), level1);
+ let mod_map = ModuleMap::new(hm);
+ proptest::prop_assert_eq!(mod_map.level_for(&s0), &level0);
+ proptest::prop_assert_eq!(mod_map.level_for(&sub), &level1);
+ }
+}
+fn filter_strategy() -> impl proptest::strategy::Strategy {
+ use proptest::strategy::Just;
+ proptest::prop_oneof![
+ Just(LevelFilter::Off),
+ Just(LevelFilter::Error),
+ Just(LevelFilter::Warn),
+ Just(LevelFilter::Info),
+ Just(LevelFilter::Debug),
+ Just(LevelFilter::Trace),
+ ]
+}