Exercise: Logger Trait

Let’s design a simple logging utility, using a trait Logger with a log method. Code which might log its progress can then take an &impl Logger. In testing, this might put messages in the test logfile, while in a production build it would send messages to a log server.

However, the StdoutLogger given below logs all messages, regardless of verbosity. Your task is to write a VerbosityFilter type that will ignore messages above a maximum verbosity.

This is a common pattern: a struct wrapping a trait implementation and implementing that same trait, adding behavior in the process. What other kinds of wrappers might be useful in a logging utility?

1. ```
   pub trait Logger {
   ```
2. ```
       /// Log a message at the given verbosity level.
   ```
3. ```
       fn log(&self, verbosity: u8, message: &str);
   ```
4. ```
   }
   ```

6. ```
   struct StdoutLogger;
   ```

8. ```
   impl Logger for StdoutLogger {
   ```
9. ```
       fn log(&self, verbosity: u8, message: &str) {
   ```
10. ```
            println!("verbosity={verbosity}: {message}");
    ```
11. ```
        }
    ```
12. ```
    }
    ```

14. ```
    // TODO: Define and implement `VerbosityFilter`.
    ```

16. ```
    fn main() {
    ```
17. ```
        let logger = VerbosityFilter { max_verbosity: 3, inner: StdoutLogger };
    ```
18. ```
        logger.log(5, "FYI");
    ```
19. ```
        logger.log(2, "Uhoh");
    ```
20. ```
    }
    ```