/ src / error_ext.rs
error_ext.rs
 1  //! Error handling extensions for more ergonomic error management.
 2  //!
 3  //! Provides extension traits for Result types that enable logging errors
 4  //! while converting to Option, avoiding silent error swallowing.
 5  
 6  use tracing::{error, warn};
 7  
 8  /// Extension trait for Result types that provides logging variants of `.ok()`.
 9  ///
10  /// Instead of silently discarding errors with `.ok()`, use these methods
11  /// to log the error before converting to Option.
12  pub trait ResultExt<T, E: std::fmt::Display> {
13      /// Convert to Option, logging the error at error level if Err.
14      ///
15      /// Use this when the error represents a significant problem that
16      /// should be investigated.
17      fn ok_logged(self, context: &str) -> Option<T>;
18  
19      /// Convert to Option, logging the error at warn level if Err.
20      ///
21      /// Use this when the error is expected in some circumstances
22      /// but should still be tracked.
23      fn ok_warn(self, context: &str) -> Option<T>;
24  }
25  
26  impl<T, E: std::fmt::Display> ResultExt<T, E> for Result<T, E> {
27      fn ok_logged(self, context: &str) -> Option<T> {
28          match self {
29              Ok(v) => Some(v),
30              Err(e) => {
31                  error!(context = %context, error = %e, "Operation failed");
32                  None
33              }
34          }
35      }
36  
37      fn ok_warn(self, context: &str) -> Option<T> {
38          match self {
39              Ok(v) => Some(v),
40              Err(e) => {
41                  warn!(context = %context, error = %e, "Operation failed (expected in some cases)");
42                  None
43              }
44          }
45      }
46  }
47  
48  #[cfg(test)]
49  mod tests {
50      use super::*;
51  
52      #[test]
53      fn test_ok_logged_with_ok() {
54          let result: Result<i32, &str> = Ok(42);
55          assert_eq!(result.ok_logged("test"), Some(42));
56      }
57  
58      #[test]
59      fn test_ok_logged_with_err() {
60          let result: Result<i32, &str> = Err("test error");
61          assert_eq!(result.ok_logged("test context"), None);
62      }
63  
64      #[test]
65      fn test_ok_warn_with_ok() {
66          let result: Result<i32, &str> = Ok(42);
67          assert_eq!(result.ok_warn("test"), Some(42));
68      }
69  
70      #[test]
71      fn test_ok_warn_with_err() {
72          let result: Result<i32, &str> = Err("test error");
73          assert_eq!(result.ok_warn("test context"), None);
74      }
75  }