cadmus_core/view/settings_editor/kinds/
telemetry.rs

1//! Setting kinds for the Telemetry category.
2
3use super::{SettingData, SettingIdentity, SettingKind, ToggleSettings, WidgetKind};
4use crate::fl;
5use crate::settings::Settings;
6use crate::view::{Bus, EntryId, EntryKind, Event, ToggleEvent};
7
8#[cfg(feature = "otel")]
9use super::InputSettingKind;
10#[cfg(feature = "otel")]
11use crate::view::ViewId;
12use std::str::FromStr;
13
14/// Logging enabled toggle setting
15pub struct LoggingEnabled;
16
17impl SettingKind for LoggingEnabled {
18    fn identity(&self) -> SettingIdentity {
19        SettingIdentity::LoggingEnabled
20    }
21
22    fn label(&self, _settings: &Settings) -> String {
23        fl!("settings-telemetry-enable-logging")
24    }
25
26    fn fetch(&self, settings: &Settings) -> SettingData {
27        SettingData {
28            value: settings.logging.enabled.to_string(),
29            widget: WidgetKind::Toggle {
30                left_label: fl!("settings-general-toggle-on"),
31                right_label: fl!("settings-general-toggle-off"),
32                enabled: settings.logging.enabled,
33                tap_event: Event::Toggle(ToggleEvent::Setting(ToggleSettings::LoggingEnabled)),
34            },
35        }
36    }
37
38    fn handle(&self, evt: &Event, settings: &mut Settings, _bus: &mut Bus) -> Option<String> {
39        if let Event::Toggle(ToggleEvent::Setting(ToggleSettings::LoggingEnabled)) = evt {
40            settings.logging.enabled = !settings.logging.enabled;
41            return Some(settings.logging.enabled.to_string());
42        }
43        None
44    }
45}
46
47/// Log level selection setting
48pub struct LogLevel;
49
50impl LogLevel {
51    fn level_to_i18n(level: &tracing::Level) -> String {
52        match *level {
53            tracing::Level::TRACE => fl!("settings-log-level-trace"),
54            tracing::Level::DEBUG => fl!("settings-log-level-debug"),
55            tracing::Level::INFO => fl!("settings-log-level-info"),
56            tracing::Level::WARN => fl!("settings-log-level-warn"),
57            tracing::Level::ERROR => fl!("settings-log-level-error"),
58        }
59    }
60}
61
62impl SettingKind for LogLevel {
63    fn identity(&self) -> SettingIdentity {
64        SettingIdentity::LogLevel
65    }
66
67    fn label(&self, _settings: &Settings) -> String {
68        fl!("settings-telemetry-log-level")
69    }
70
71    fn fetch(&self, settings: &Settings) -> SettingData {
72        let current = tracing::Level::from_str(settings.logging.level.as_str())
73            .unwrap_or(tracing::Level::INFO);
74
75        let entries = vec![
76            EntryKind::RadioButton(
77                Self::level_to_i18n(&tracing::Level::TRACE),
78                EntryId::SetLogLevel(tracing::Level::TRACE),
79                current == tracing::Level::TRACE,
80            ),
81            EntryKind::RadioButton(
82                Self::level_to_i18n(&tracing::Level::DEBUG),
83                EntryId::SetLogLevel(tracing::Level::DEBUG),
84                current == tracing::Level::DEBUG,
85            ),
86            EntryKind::RadioButton(
87                Self::level_to_i18n(&tracing::Level::INFO),
88                EntryId::SetLogLevel(tracing::Level::INFO),
89                current == tracing::Level::INFO,
90            ),
91            EntryKind::RadioButton(
92                Self::level_to_i18n(&tracing::Level::WARN),
93                EntryId::SetLogLevel(tracing::Level::WARN),
94                current == tracing::Level::WARN,
95            ),
96            EntryKind::RadioButton(
97                Self::level_to_i18n(&tracing::Level::ERROR),
98                EntryId::SetLogLevel(tracing::Level::ERROR),
99                current == tracing::Level::ERROR,
100            ),
101        ];
102
103        SettingData {
104            value: Self::level_to_i18n(&current),
105            widget: WidgetKind::SubMenu(entries),
106        }
107    }
108
109    fn handle(&self, evt: &Event, settings: &mut Settings, _bus: &mut Bus) -> Option<String> {
110        if let Event::Select(EntryId::SetLogLevel(ref level)) = evt {
111            settings.logging.level = level.to_string();
112            return Some(Self::level_to_i18n(level));
113        }
114        None
115    }
116}
117
118/// OTLP endpoint configuration setting (otel feature)
119#[cfg(feature = "otel")]
120pub struct OtlpEndpoint;
121
122#[cfg(feature = "otel")]
123impl SettingKind for OtlpEndpoint {
124    fn identity(&self) -> SettingIdentity {
125        SettingIdentity::OtlpEndpoint
126    }
127
128    fn label(&self, _settings: &Settings) -> String {
129        fl!("settings-telemetry-otlp-endpoint")
130    }
131
132    fn fetch(&self, settings: &Settings) -> SettingData {
133        let value = settings
134            .logging
135            .otlp_endpoint
136            .clone()
137            .unwrap_or_else(|| fl!("settings-general-not-set"));
138
139        SettingData {
140            value,
141            widget: WidgetKind::ActionLabel(Event::Select(EntryId::EditOtlpEndpoint)),
142        }
143    }
144
145    fn as_input_kind(&self) -> Option<&dyn InputSettingKind> {
146        Some(self)
147    }
148}
149
150#[cfg(feature = "otel")]
151impl InputSettingKind for OtlpEndpoint {
152    fn submit_view_id(&self) -> ViewId {
153        ViewId::OtlpEndpointInput
154    }
155
156    fn open_entry_id(&self) -> EntryId {
157        EntryId::EditOtlpEndpoint
158    }
159
160    fn input_label(&self) -> String {
161        fl!("settings-telemetry-otlp-endpoint")
162    }
163
164    fn input_max_chars(&self) -> usize {
165        50
166    }
167
168    fn current_text(&self, settings: &Settings) -> String {
169        settings.logging.otlp_endpoint.clone().unwrap_or_default()
170    }
171
172    fn apply_text(&self, text: &str, settings: &mut Settings) -> String {
173        let trimmed = text.trim();
174        settings.logging.otlp_endpoint = if trimmed.is_empty() {
175            None
176        } else {
177            Some(trimmed.to_string())
178        };
179        settings
180            .logging
181            .otlp_endpoint
182            .clone()
183            .unwrap_or_else(|| fl!("settings-general-not-set"))
184    }
185}
186
187/// Kernel logging toggle setting (test + kobo features)
188#[cfg(all(feature = "test", feature = "kobo"))]
189pub struct EnableKernLog;
190
191#[cfg(all(feature = "test", feature = "kobo"))]
192impl SettingKind for EnableKernLog {
193    fn identity(&self) -> SettingIdentity {
194        SettingIdentity::EnableKernLog
195    }
196
197    fn label(&self, _settings: &Settings) -> String {
198        fl!("settings-telemetry-enable-kernel-log")
199    }
200
201    fn fetch(&self, settings: &Settings) -> SettingData {
202        SettingData {
203            value: settings.logging.enable_kern_log.to_string(),
204            widget: WidgetKind::Toggle {
205                left_label: fl!("settings-general-toggle-on"),
206                right_label: fl!("settings-general-toggle-off"),
207                enabled: settings.logging.enable_kern_log,
208                tap_event: Event::Toggle(ToggleEvent::Setting(ToggleSettings::EnableKernLog)),
209            },
210        }
211    }
212
213    fn handle(&self, evt: &Event, settings: &mut Settings, _bus: &mut Bus) -> Option<String> {
214        if let Event::Toggle(ToggleEvent::Setting(ToggleSettings::EnableKernLog)) = evt {
215            settings.logging.enable_kern_log = !settings.logging.enable_kern_log;
216            return Some(settings.logging.enable_kern_log.to_string());
217        }
218        None
219    }
220}
221
222/// D-Bus logging toggle setting (test + kobo features)
223#[cfg(all(feature = "test", feature = "kobo"))]
224pub struct EnableDbusLog;
225
226#[cfg(all(feature = "test", feature = "kobo"))]
227impl SettingKind for EnableDbusLog {
228    fn identity(&self) -> SettingIdentity {
229        SettingIdentity::EnableDbusLog
230    }
231
232    fn label(&self, _settings: &Settings) -> String {
233        fl!("settings-telemetry-enable-dbus-log")
234    }
235
236    fn fetch(&self, settings: &Settings) -> SettingData {
237        SettingData {
238            value: settings.logging.enable_dbus_log.to_string(),
239            widget: WidgetKind::Toggle {
240                left_label: fl!("settings-general-toggle-on"),
241                right_label: fl!("settings-general-toggle-off"),
242                enabled: settings.logging.enable_dbus_log,
243                tap_event: Event::Toggle(ToggleEvent::Setting(ToggleSettings::EnableDbusLog)),
244            },
245        }
246    }
247
248    fn handle(&self, evt: &Event, settings: &mut Settings, _bus: &mut Bus) -> Option<String> {
249        if let Event::Toggle(ToggleEvent::Setting(ToggleSettings::EnableDbusLog)) = evt {
250            settings.logging.enable_dbus_log = !settings.logging.enable_dbus_log;
251            return Some(settings.logging.enable_dbus_log.to_string());
252        }
253        None
254    }
255}
256
257#[cfg(test)]
258mod tests {
259    use super::*;
260    use crate::settings::Settings;
261    use crate::view::settings_editor::kinds::ToggleSettings;
262    use crate::view::{Bus, EntryId, Event, ToggleEvent};
263    use std::collections::VecDeque;
264
265    mod logging_enabled {
266        use super::*;
267
268        #[test]
269        fn handle_toggle_disables_when_enabled() {
270            let setting = LoggingEnabled;
271            let mut settings = Settings::default();
272            settings.logging.enabled = true;
273            let mut bus: Bus = VecDeque::new();
274            let event = Event::Toggle(ToggleEvent::Setting(ToggleSettings::LoggingEnabled));
275
276            let result = setting.handle(&event, &mut settings, &mut bus);
277
278            assert!(result.is_some());
279            assert!(!settings.logging.enabled);
280        }
281
282        #[test]
283        fn handle_toggle_enables_when_disabled() {
284            let setting = LoggingEnabled;
285            let mut settings = Settings::default();
286            settings.logging.enabled = false;
287            let mut bus: Bus = VecDeque::new();
288            let event = Event::Toggle(ToggleEvent::Setting(ToggleSettings::LoggingEnabled));
289
290            let result = setting.handle(&event, &mut settings, &mut bus);
291
292            assert!(result.is_some());
293            assert!(settings.logging.enabled);
294        }
295
296        #[test]
297        fn handle_returns_none_for_wrong_event() {
298            let setting = LoggingEnabled;
299            let mut settings = Settings::default();
300            let mut bus: Bus = VecDeque::new();
301
302            let result = setting.handle(&Event::Select(EntryId::About), &mut settings, &mut bus);
303
304            assert!(result.is_none());
305        }
306
307        #[test]
308        fn handle_returns_none_for_wrong_toggle() {
309            let setting = LoggingEnabled;
310            let mut settings = Settings::default();
311            let mut bus: Bus = VecDeque::new();
312
313            let result = setting.handle(
314                &Event::Toggle(ToggleEvent::Setting(ToggleSettings::SleepCover)),
315                &mut settings,
316                &mut bus,
317            );
318
319            assert!(result.is_none());
320        }
321    }
322
323    mod log_level {
324        use super::*;
325
326        #[test]
327        fn handle_set_level_updates_settings() {
328            let setting = LogLevel;
329            let mut settings = Settings::default();
330            settings.logging.level = "INFO".to_string();
331            let mut bus: Bus = VecDeque::new();
332            let event = Event::Select(EntryId::SetLogLevel(tracing::Level::WARN));
333
334            let result = setting.handle(&event, &mut settings, &mut bus);
335
336            assert!(result.is_some());
337            assert_eq!(settings.logging.level, "WARN");
338        }
339
340        #[test]
341        fn handle_can_set_all_levels() {
342            let setting = LogLevel;
343            let mut settings = Settings::default();
344            let mut bus: Bus = VecDeque::new();
345
346            for level in [
347                tracing::Level::TRACE,
348                tracing::Level::DEBUG,
349                tracing::Level::INFO,
350                tracing::Level::WARN,
351                tracing::Level::ERROR,
352            ] {
353                let event = Event::Select(EntryId::SetLogLevel(level));
354                setting.handle(&event, &mut settings, &mut bus);
355                assert_eq!(settings.logging.level, level.to_string());
356            }
357        }
358
359        #[test]
360        fn handle_returns_none_for_wrong_event() {
361            let setting = LogLevel;
362            let mut settings = Settings::default();
363            let mut bus: Bus = VecDeque::new();
364
365            let result = setting.handle(&Event::Select(EntryId::About), &mut settings, &mut bus);
366
367            assert!(result.is_none());
368        }
369    }
370
371    #[cfg(feature = "otel")]
372    mod otlp_endpoint {
373        use super::*;
374        use crate::view::settings_editor::kinds::InputSettingKind;
375
376        #[test]
377        fn apply_text_sets_endpoint() {
378            let setting = OtlpEndpoint;
379            let mut settings = Settings::default();
380
381            let display = setting.apply_text("http://otel:4317", &mut settings);
382
383            assert_eq!(display, "http://otel:4317");
384            assert_eq!(
385                settings.logging.otlp_endpoint,
386                Some("http://otel:4317".to_string())
387            );
388        }
389
390        #[test]
391        fn apply_text_trims_whitespace() {
392            let setting = OtlpEndpoint;
393            let mut settings = Settings::default();
394
395            let display = setting.apply_text("  http://otel:4317  ", &mut settings);
396
397            assert_eq!(display, "http://otel:4317");
398            assert_eq!(
399                settings.logging.otlp_endpoint,
400                Some("http://otel:4317".to_string())
401            );
402        }
403
404        #[test]
405        fn apply_text_empty_clears_endpoint() {
406            let setting = OtlpEndpoint;
407            let mut settings = Settings::default();
408            settings.logging.otlp_endpoint = Some("http://old:4317".to_string());
409
410            let display = setting.apply_text("", &mut settings);
411
412            assert_eq!(display, "Not set");
413            assert_eq!(settings.logging.otlp_endpoint, None);
414        }
415
416        #[test]
417        fn apply_text_whitespace_only_clears_endpoint() {
418            let setting = OtlpEndpoint;
419            let mut settings = Settings::default();
420            settings.logging.otlp_endpoint = Some("http://old:4317".to_string());
421
422            let display = setting.apply_text("   ", &mut settings);
423
424            assert_eq!(display, "Not set");
425            assert_eq!(settings.logging.otlp_endpoint, None);
426        }
427    }
428
429    #[cfg(feature = "test")]
430    mod enable_kern_log {
431        use super::*;
432
433        #[test]
434        fn handle_toggle_enables_when_disabled() {
435            let setting = EnableKernLog;
436            let mut settings = Settings::default();
437            settings.logging.enable_kern_log = false;
438            let mut bus: Bus = VecDeque::new();
439            let event = Event::Toggle(ToggleEvent::Setting(ToggleSettings::EnableKernLog));
440
441            let result = setting.handle(&event, &mut settings, &mut bus);
442
443            assert!(result.is_some());
444            assert!(settings.logging.enable_kern_log);
445        }
446
447        #[test]
448        fn handle_toggle_disables_when_enabled() {
449            let setting = EnableKernLog;
450            let mut settings = Settings::default();
451            settings.logging.enable_kern_log = true;
452            let mut bus: Bus = VecDeque::new();
453            let event = Event::Toggle(ToggleEvent::Setting(ToggleSettings::EnableKernLog));
454
455            let result = setting.handle(&event, &mut settings, &mut bus);
456
457            assert!(result.is_some());
458            assert!(!settings.logging.enable_kern_log);
459        }
460
461        #[test]
462        fn handle_returns_none_for_wrong_event() {
463            let setting = EnableKernLog;
464            let mut settings = Settings::default();
465            let mut bus: Bus = VecDeque::new();
466
467            let result = setting.handle(&Event::Select(EntryId::About), &mut settings, &mut bus);
468
469            assert!(result.is_none());
470        }
471
472        #[test]
473        fn handle_returns_none_for_wrong_toggle() {
474            let setting = EnableKernLog;
475            let mut settings = Settings::default();
476            let mut bus: Bus = VecDeque::new();
477
478            let result = setting.handle(
479                &Event::Toggle(ToggleEvent::Setting(ToggleSettings::LoggingEnabled)),
480                &mut settings,
481                &mut bus,
482            );
483
484            assert!(result.is_none());
485        }
486    }
487
488    #[cfg(all(feature = "test", feature = "kobo"))]
489    mod enable_dbus_log {
490        use super::*;
491
492        #[test]
493        fn handle_toggle_enables_when_disabled() {
494            let setting = EnableDbusLog;
495            let mut settings = Settings::default();
496            settings.logging.enable_dbus_log = false;
497            let mut bus: Bus = VecDeque::new();
498            let event = Event::Toggle(ToggleEvent::Setting(ToggleSettings::EnableDbusLog));
499
500            let result = setting.handle(&event, &mut settings, &mut bus);
501
502            assert!(result.is_some());
503            assert!(settings.logging.enable_dbus_log);
504        }
505
506        #[test]
507        fn handle_toggle_disables_when_enabled() {
508            let setting = EnableDbusLog;
509            let mut settings = Settings::default();
510            settings.logging.enable_dbus_log = true;
511            let mut bus: Bus = VecDeque::new();
512            let event = Event::Toggle(ToggleEvent::Setting(ToggleSettings::EnableDbusLog));
513
514            let result = setting.handle(&event, &mut settings, &mut bus);
515
516            assert!(result.is_some());
517            assert!(!settings.logging.enable_dbus_log);
518        }
519
520        #[test]
521        fn handle_returns_none_for_wrong_event() {
522            let setting = EnableDbusLog;
523            let mut settings = Settings::default();
524            let mut bus: Bus = VecDeque::new();
525
526            let result = setting.handle(&Event::Select(EntryId::About), &mut settings, &mut bus);
527
528            assert!(result.is_none());
529        }
530
531        #[test]
532        fn handle_returns_none_for_wrong_toggle() {
533            let setting = EnableDbusLog;
534            let mut settings = Settings::default();
535            let mut bus: Bus = VecDeque::new();
536
537            let result = setting.handle(
538                &Event::Toggle(ToggleEvent::Setting(ToggleSettings::LoggingEnabled)),
539                &mut settings,
540                &mut bus,
541            );
542
543            assert!(result.is_none());
544        }
545    }
546}