Skip to main content

studiole_logging/registration/
logger_factory.rs

1//! Factory for constructing a [`Logger`] from the DI container.
2use crate::prelude::*;
3
4/// Factory that produces a [`Logger`] by resolving dependencies from a [`ServiceProvider`].
5pub(crate) struct LoggerFactory {
6    /// Factory function receiving the service provider.
7    pub factory: fn(&ServiceProvider) -> Result<Logger, Report<ResolveError>>,
8}
9
10impl LoggerFactory {
11    /// Create a new [`LoggerFactory`] from a factory function.
12    pub fn new(factory: fn(&ServiceProvider) -> Result<Logger, Report<ResolveError>>) -> Self {
13        Self { factory }
14    }
15}
16
17impl FromServices for Logger {
18    type Error = ResolveError;
19
20    fn from_services(services: &ServiceProvider) -> Result<Self, Report<Self::Error>> {
21        let factory = services.get::<LoggerFactory>()?;
22        (factory.factory)(services)
23    }
24}
25
26#[cfg(test)]
27mod tests {
28    use super::*;
29
30    struct TestConfig {
31        pub level: LogLevel,
32    }
33
34    #[test]
35    fn logger_resolves_via_factory() {
36        // Arrange
37        let services = ServiceBuilder::new()
38            .with_instance(TestConfig {
39                level: LogLevel::Debug,
40            })
41            .with_instance(LoggerFactory::new(|services| {
42                let config = services.get::<TestConfig>()?;
43                Ok(LoggerBuilder::new().with_level(config.level).build())
44            }))
45            .with_type::<Logger>()
46            .build();
47        // Act
48        let logger = services.get::<Logger>();
49        // Assert
50        assert!(logger.is_ok());
51        assert_eq!(logger.expect("should resolve").level, LogLevel::Debug);
52    }
53
54    #[test]
55    fn end_to_end_with_logging_sugar() {
56        // Arrange
57        struct CliOptions {
58            pub log_level: LogLevel,
59        }
60        let services = ServiceBuilder::new()
61            .with_instance(CliOptions {
62                log_level: LogLevel::Warn,
63            })
64            .with_logging(|services| {
65                let cli = services.get::<CliOptions>()?;
66                Ok(LoggerBuilder::new()
67                    .with_level(cli.log_level)
68                    .with_target("sqlx", LogLevel::Error)
69                    .with_target("hyper", LogLevel::Error)
70                    .build())
71            })
72            .build();
73        // Act
74        let logger = services.expect::<Logger>();
75        // Assert
76        assert_eq!(logger.level, LogLevel::Warn);
77        assert_eq!(logger.targets.len(), 2);
78    }
79}