turul_mcp_protocol_2025_06_18/
logging.rs1use serde::{Deserialize, Serialize};
6use serde_json::Value;
7use std::collections::HashMap;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "lowercase")]
13pub enum LoggingLevel {
14 Debug,
15 Info,
16 Notice,
17 Warning,
18 Error,
19 Critical,
20 Alert,
21 Emergency,
22}
23
24pub type LogLevel = LoggingLevel;
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29#[serde(rename_all = "camelCase")]
30pub struct LoggingMessageParams {
31 pub level: LoggingLevel,
33 #[serde(skip_serializing_if = "Option::is_none")]
35 pub logger: Option<String>,
36 pub data: Value,
38 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
40 pub meta: Option<HashMap<String, Value>>,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
45#[serde(rename_all = "camelCase")]
46pub struct LoggingMessageNotification {
47 pub method: String,
49 pub params: LoggingMessageParams,
51}
52
53impl LoggingMessageParams {
54 pub fn new(level: LoggingLevel, data: Value) -> Self {
55 Self {
56 level,
57 logger: None,
58 data,
59 meta: None,
60 }
61 }
62
63 pub fn with_logger(mut self, logger: impl Into<String>) -> Self {
64 self.logger = Some(logger.into());
65 self
66 }
67
68 pub fn with_meta(mut self, meta: HashMap<String, Value>) -> Self {
69 self.meta = Some(meta);
70 self
71 }
72}
73
74impl LoggingMessageNotification {
75 pub fn new(level: LoggingLevel, data: Value) -> Self {
76 Self {
77 method: "notifications/message".to_string(),
78 params: LoggingMessageParams::new(level, data),
79 }
80 }
81
82 pub fn with_logger(mut self, logger: impl Into<String>) -> Self {
83 self.params = self.params.with_logger(logger);
84 self
85 }
86
87 pub fn with_meta(mut self, meta: HashMap<String, Value>) -> Self {
88 self.params = self.params.with_meta(meta);
89 self
90 }
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
95#[serde(rename_all = "camelCase")]
96pub struct SetLevelParams {
97 pub level: LoggingLevel,
99 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
101 pub meta: Option<HashMap<String, Value>>,
102}
103
104impl SetLevelParams {
105 pub fn new(level: LoggingLevel) -> Self {
106 Self { level, meta: None }
107 }
108
109 pub fn with_meta(mut self, meta: HashMap<String, Value>) -> Self {
110 self.meta = Some(meta);
111 self
112 }
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
117#[serde(rename_all = "camelCase")]
118pub struct SetLevelRequest {
119 pub method: String,
121 pub params: SetLevelParams,
123}
124
125impl SetLevelRequest {
126 pub fn new(level: LoggingLevel) -> Self {
127 Self {
128 method: "logging/setLevel".to_string(),
129 params: SetLevelParams::new(level),
130 }
131 }
132
133 pub fn with_meta(mut self, meta: HashMap<String, Value>) -> Self {
134 self.params = self.params.with_meta(meta);
135 self
136 }
137}
138
139impl LoggingLevel {
141 pub fn priority(&self) -> u8 {
143 match self {
144 LoggingLevel::Debug => 0,
145 LoggingLevel::Info => 1,
146 LoggingLevel::Notice => 2,
147 LoggingLevel::Warning => 3,
148 LoggingLevel::Error => 4,
149 LoggingLevel::Critical => 5,
150 LoggingLevel::Alert => 6,
151 LoggingLevel::Emergency => 7,
152 }
153 }
154
155 pub fn should_log(&self, threshold: LoggingLevel) -> bool {
157 self.priority() >= threshold.priority()
158 }
159}
160
161use crate::traits::*;
163
164impl Params for SetLevelParams {}
166impl Params for LoggingMessageParams {}
167
168impl HasLevelParam for SetLevelParams {
170 fn level(&self) -> &LoggingLevel {
171 &self.level
172 }
173}
174
175impl HasMetaParam for SetLevelParams {
176 fn meta(&self) -> Option<&HashMap<String, Value>> {
177 self.meta.as_ref()
178 }
179}
180
181impl HasMethod for SetLevelRequest {
183 fn method(&self) -> &str {
184 &self.method
185 }
186}
187
188impl HasParams for SetLevelRequest {
189 fn params(&self) -> Option<&dyn Params> {
190 Some(&self.params)
191 }
192}
193
194impl HasLevelParam for LoggingMessageParams {
196 fn level(&self) -> &LoggingLevel {
197 &self.level
198 }
199}
200
201impl HasLoggerParam for LoggingMessageParams {
202 fn logger(&self) -> Option<&String> {
203 self.logger.as_ref()
204 }
205}
206
207impl HasMetaParam for LoggingMessageParams {
208 fn meta(&self) -> Option<&HashMap<String, Value>> {
209 self.meta.as_ref()
210 }
211}
212
213impl HasMethod for LoggingMessageNotification {
215 fn method(&self) -> &str {
216 &self.method
217 }
218}
219
220impl HasParams for LoggingMessageNotification {
221 fn params(&self) -> Option<&dyn Params> {
222 Some(&self.params)
223 }
224}
225
226#[cfg(test)]
233mod tests {
234 use super::*;
235 use serde_json::json;
236
237 #[test]
238 fn test_logging_level_priority() {
239 assert_eq!(LoggingLevel::Debug.priority(), 0);
240 assert_eq!(LoggingLevel::Emergency.priority(), 7);
241
242 assert!(LoggingLevel::Error.should_log(LoggingLevel::Warning));
243 assert!(!LoggingLevel::Info.should_log(LoggingLevel::Error));
244 }
245
246 #[test]
247 fn test_set_level_request() {
248 let request = SetLevelRequest::new(LoggingLevel::Warning);
249
250 assert_eq!(request.method, "logging/setLevel");
251 assert_eq!(request.params.level, LoggingLevel::Warning);
252 }
253
254 #[test]
255 fn test_logging_message_notification() {
256 let data = json!({"message": "Test log message", "context": "test"});
257 let notification = LoggingMessageNotification::new(LoggingLevel::Info, data.clone())
258 .with_logger("test-logger");
259
260 assert_eq!(notification.method, "notifications/message");
261 assert_eq!(notification.params.level, LoggingLevel::Info);
262 assert_eq!(notification.params.logger, Some("test-logger".to_string()));
263 assert_eq!(notification.params.data, data);
264 }
265
266 #[test]
267 fn test_serialization() {
268 let request = SetLevelRequest::new(LoggingLevel::Error);
269 let json = serde_json::to_string(&request).unwrap();
270 assert!(json.contains("logging/setLevel"));
271 assert!(json.contains("error"));
272
273 let parsed: SetLevelRequest = serde_json::from_str(&json).unwrap();
274 assert_eq!(parsed.method, "logging/setLevel");
275 assert_eq!(parsed.params.level, LoggingLevel::Error);
276 }
277}