1use aspect_core::{Aspect, AspectError, JoinPoint};
4use std::any::Any;
5
6#[derive(Clone)]
22pub struct LoggingAspect {
23 level: LogLevel,
24 log_args: bool,
25 log_result: bool,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum LogLevel {
31 Trace,
33 Debug,
35 Info,
37 Warn,
39 Error,
41}
42
43impl LoggingAspect {
44 pub fn new() -> Self {
46 Self {
47 level: LogLevel::Info,
48 log_args: false,
49 log_result: false,
50 }
51 }
52
53 pub fn with_level(mut self, level: LogLevel) -> Self {
55 self.level = level;
56 self
57 }
58
59 pub fn log_args(mut self) -> Self {
61 self.log_args = true;
62 self
63 }
64
65 pub fn log_result(mut self) -> Self {
67 self.log_result = true;
68 self
69 }
70
71 fn log(&self, level: LogLevel, message: &str) {
72 if level as u8 >= self.level as u8 {
73 match level {
74 LogLevel::Trace => log::trace!("{}", message),
75 LogLevel::Debug => log::debug!("{}", message),
76 LogLevel::Info => log::info!("{}", message),
77 LogLevel::Warn => log::warn!("{}", message),
78 LogLevel::Error => log::error!("{}", message),
79 }
80 }
81 }
82}
83
84impl Default for LoggingAspect {
85 fn default() -> Self {
86 Self::new()
87 }
88}
89
90impl Aspect for LoggingAspect {
91 fn before(&self, ctx: &JoinPoint) {
92 let message = format!(
93 "[ENTRY] {} ({}:{})",
94 ctx.function_name, ctx.location.file, ctx.location.line
95 );
96 self.log(self.level, &message);
97 }
98
99 fn after(&self, ctx: &JoinPoint, result: &dyn Any) {
100 let mut message = format!("[EXIT] {}", ctx.function_name);
101
102 if self.log_result {
103 message.push_str(&format!(" (result: {:?})", std::any::type_name_of_val(result)));
104 }
105
106 self.log(self.level, &message);
107 }
108
109 fn after_error(&self, ctx: &JoinPoint, error: &AspectError) {
110 let message = format!("[ERROR] {} failed: {:?}", ctx.function_name, error);
111 self.log(LogLevel::Error, &message);
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn test_logging_aspect_creation() {
121 let aspect = LoggingAspect::new();
122 assert_eq!(aspect.level, LogLevel::Info);
123 assert!(!aspect.log_args);
124 assert!(!aspect.log_result);
125 }
126
127 #[test]
128 fn test_logging_aspect_builder() {
129 let aspect = LoggingAspect::new()
130 .with_level(LogLevel::Debug)
131 .log_args()
132 .log_result();
133
134 assert_eq!(aspect.level, LogLevel::Debug);
135 assert!(aspect.log_args);
136 assert!(aspect.log_result);
137 }
138
139 #[test]
140 fn test_logging_aspect_before() {
141 let aspect = LoggingAspect::new();
142 let ctx = JoinPoint {
143 function_name: "test_function",
144 module_path: "test::module",
145 location: aspect_core::Location {
146 file: "test.rs",
147 line: 42,
148 },
149 };
150
151 aspect.before(&ctx);
153 }
154}