Skip to main content

ferroui_splat/logging/
default_log_manager.rs

1//! `DefaultLogManager`.
2
3use super::{
4    IFullLogger, ILogManager, ILogger, LoggingException, MemoizingMRUCache, NullLogger,
5    WrappingFullLogger, WrappingPrefixLogger,
6};
7use crate::service_location::{IReadonlyDependencyResolver, ReadonlyDependencyResolverExt};
8use std::rc::Rc;
9
10const LOGGER_CACHE_SIZE: usize = 64;
11
12/// The log manager Splat registers (`DefaultLogManager`): the logger of a type is the `dyn ILogger`
13/// of the resolver, with the name of the type in front of its messages, wrapped in a full logger.
14/// The last 64 loggers are cached.
15pub struct DefaultLogManager {
16    logger_cache: MemoizingMRUCache<&'static str, Rc<dyn IFullLogger>>,
17    null_logger: Rc<dyn IFullLogger>,
18}
19
20impl DefaultLogManager {
21    /// A log manager over the loggers of `dependency_resolver`.
22    ///
23    /// Getting a logger panics with a [`LoggingException`] when the resolver has no `dyn ILogger`.
24    pub fn new(dependency_resolver: Rc<dyn IReadonlyDependencyResolver>) -> Self {
25        let logger_cache = MemoizingMRUCache::new(
26            move |type_name: &&'static str, _context| -> Rc<dyn IFullLogger> {
27                match dependency_resolver.get_service::<dyn ILogger>() {
28                    None => std::panic::panic_any(LoggingException::with_message(
29                        "Couldn't find an ILogger. This should never happen, your dependency resolver is probably broken.",
30                    )),
31                    Some(logger) => Rc::new(WrappingFullLogger::new(Rc::new(WrappingPrefixLogger::new(
32                        logger, *type_name,
33                    )))),
34                }
35            },
36            LOGGER_CACHE_SIZE,
37        );
38        Self { logger_cache, null_logger: Rc::new(WrappingFullLogger::new(Rc::new(NullLogger::new()))) }
39    }
40}
41
42impl ILogManager for DefaultLogManager {
43    fn get_logger(&self, type_name: &'static str) -> Rc<dyn IFullLogger> {
44        // The cache's own logger would log through the cache.
45        if type_name == std::any::type_name::<MemoizingMRUCache<&'static str, Rc<dyn IFullLogger>>>() {
46            return self.null_logger.clone();
47        }
48        self.logger_cache.get(type_name)
49    }
50}